-
Notifications
You must be signed in to change notification settings - Fork 1.9k
/
Copy pathJSDispatcher.kt
90 lines (69 loc) · 2.91 KB
/
JSDispatcher.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
package kotlinx.coroutines
import kotlin.js.*
internal actual abstract external class W3CWindow {
fun clearTimeout(handle: Int)
}
internal actual fun w3cSetTimeout(window: W3CWindow, handler: () -> Unit, timeout: Int): Int =
setTimeout(window, handler, timeout)
internal actual fun w3cSetTimeout(handler: () -> Unit, timeout: Int): Int =
setTimeout(handler, timeout)
internal actual fun w3cClearTimeout(window: W3CWindow, handle: Int) =
window.clearTimeout(handle)
internal actual fun w3cClearTimeout(handle: Int) =
clearTimeout(handle)
internal actual class ScheduledMessageQueue actual constructor(private val dispatcher: SetTimeoutBasedDispatcher) : MessageQueue() {
internal val processQueue: () -> Unit = ::process
actual override fun schedule() {
dispatcher.scheduleQueueProcessing()
}
actual override fun reschedule() {
setTimeout(processQueue, 0)
}
internal actual fun setTimeout(timeout: Int) {
setTimeout(processQueue, timeout)
}
}
internal class NodeDispatcher(private val process: JsProcess) : SetTimeoutBasedDispatcher() {
override fun scheduleQueueProcessing() {
process.nextTick(messageQueue.processQueue)
}
}
@Suppress("UNUSED_PARAMETER")
private fun subscribeToWindowMessages(window: W3CWindow, process: () -> Unit): Unit = js("""{
const handler = (event) => {
if (event.source == window && event.data == 'dispatchCoroutine') {
event.stopPropagation();
process();
}
}
window.addEventListener('message', handler, true);
}""")
@Suppress("UNUSED_PARAMETER")
private fun createRescheduleMessagePoster(window: W3CWindow): () -> Unit =
js("() => window.postMessage('dispatchCoroutine', '*')")
@Suppress("UNUSED_PARAMETER")
private fun createScheduleMessagePoster(process: () -> Unit): () -> Unit =
js("() => Promise.resolve(0).then(process)")
internal actual class WindowMessageQueue actual constructor(window: W3CWindow) : MessageQueue() {
private val scheduleMessagePoster = createScheduleMessagePoster(::process)
private val rescheduleMessagePoster = createRescheduleMessagePoster(window)
init {
subscribeToWindowMessages(window, ::process)
}
actual override fun schedule() {
scheduleMessagePoster()
}
actual override fun reschedule() {
rescheduleMessagePoster()
}
}
// We need to reference global setTimeout and clearTimeout so that it works on Node.JS as opposed to
// using them via "window" (which only works in browser)
private external fun setTimeout(handler: () -> Unit, timeout: Int): Int
// d8 doesn't have clearTimeout
@Suppress("UNUSED_PARAMETER")
private fun clearTimeout(handle: Int): Unit =
js("{ if (typeof clearTimeout !== 'undefined') clearTimeout(handle); }")
@Suppress("UNUSED_PARAMETER")
private fun setTimeout(window: W3CWindow, handler: () -> Unit, timeout: Int): Int =
js("window.setTimeout(handler, timeout)")