4
4
5
5
package kotlinx.coroutines
6
6
7
- import kotlinx.coroutines.internal.*
8
7
import org.w3c.dom.*
9
- import kotlin.coroutines.*
10
8
import kotlin.js.Promise
11
9
12
- private const val MAX_DELAY = Int .MAX_VALUE .toLong()
10
+ internal class ScheduledMessageQueue (private val dispatcher : SetTimeoutBasedDispatcher ) : MessageQueue() {
11
+ val processQueue: dynamic = { process() }
13
12
14
- private fun delayToInt (timeMillis : Long ): Int =
15
- timeMillis.coerceIn(0 , MAX_DELAY ).toInt()
16
-
17
- internal sealed class SetTimeoutBasedDispatcher : CoroutineDispatcher (), Delay {
18
- inner class ScheduledMessageQueue : MessageQueue () {
19
- internal val processQueue: dynamic = { process() }
20
-
21
- override fun schedule () {
22
- scheduleQueueProcessing()
23
- }
24
-
25
- override fun reschedule () {
26
- setTimeout(processQueue, 0 )
27
- }
28
- }
29
-
30
- internal val messageQueue = ScheduledMessageQueue ()
31
-
32
- abstract fun scheduleQueueProcessing ()
33
-
34
- override fun limitedParallelism (parallelism : Int ): CoroutineDispatcher {
35
- parallelism.checkParallelism()
36
- return this
37
- }
38
-
39
- override fun dispatch (context : CoroutineContext , block : Runnable ) {
40
- messageQueue.enqueue(block)
41
- }
42
-
43
- override fun invokeOnTimeout (timeMillis : Long , block : Runnable , context : CoroutineContext ): DisposableHandle {
44
- val handle = setTimeout({ block.run () }, delayToInt(timeMillis))
45
- return ClearTimeout (handle)
13
+ override fun schedule () {
14
+ dispatcher.scheduleQueueProcessing()
46
15
}
47
16
48
- override fun scheduleResumeAfterDelay (timeMillis : Long , continuation : CancellableContinuation <Unit >) {
49
- val handle = setTimeout({ with (continuation) { resumeUndispatched(Unit ) } }, delayToInt(timeMillis))
50
- continuation.invokeOnCancellation(handler = ClearTimeout (handle).asHandler)
17
+ override fun reschedule () {
18
+ setTimeout(processQueue, 0 )
51
19
}
52
20
}
53
21
@@ -57,48 +25,7 @@ internal object NodeDispatcher : SetTimeoutBasedDispatcher() {
57
25
}
58
26
}
59
27
60
- internal object SetTimeoutDispatcher : SetTimeoutBasedDispatcher() {
61
- override fun scheduleQueueProcessing () {
62
- setTimeout(messageQueue.processQueue, 0 )
63
- }
64
- }
65
-
66
- private open class ClearTimeout (protected val handle : Int ) : CancelHandler(), DisposableHandle {
67
-
68
- override fun dispose () {
69
- clearTimeout(handle)
70
- }
71
-
72
- override fun invoke (cause : Throwable ? ) {
73
- dispose()
74
- }
75
-
76
- override fun toString (): String = " ClearTimeout[$handle ]"
77
- }
78
-
79
- internal class WindowDispatcher (private val window : Window ) : CoroutineDispatcher(), Delay {
80
- private val queue = WindowMessageQueue (window)
81
-
82
- override fun dispatch (context : CoroutineContext , block : Runnable ) = queue.enqueue(block)
83
-
84
- override fun scheduleResumeAfterDelay (timeMillis : Long , continuation : CancellableContinuation <Unit >) {
85
- val handle = window.setTimeout({ with (continuation) { resumeUndispatched(Unit ) } }, delayToInt(timeMillis))
86
- continuation.invokeOnCancellation(handler = WindowClearTimeout (handle).asHandler)
87
- }
88
-
89
- override fun invokeOnTimeout (timeMillis : Long , block : Runnable , context : CoroutineContext ): DisposableHandle {
90
- val handle = window.setTimeout({ block.run () }, delayToInt(timeMillis))
91
- return WindowClearTimeout (handle)
92
- }
93
-
94
- private inner class WindowClearTimeout (handle : Int ) : ClearTimeout(handle) {
95
- override fun dispose () {
96
- window.clearTimeout(handle)
97
- }
98
- }
99
- }
100
-
101
- private class WindowMessageQueue (private val window : Window ) : MessageQueue() {
28
+ internal class WindowMessageQueue (private val window : Window ) : MessageQueue() {
102
29
private val messageName = " dispatchCoroutine"
103
30
104
31
init {
@@ -119,52 +46,9 @@ private class WindowMessageQueue(private val window: Window) : MessageQueue() {
119
46
}
120
47
}
121
48
122
- /* *
123
- * An abstraction over JS scheduling mechanism that leverages micro-batching of dispatched blocks without
124
- * paying the cost of JS callbacks scheduling on every dispatch.
125
- *
126
- * Queue uses two scheduling mechanisms:
127
- * 1) [schedule] is used to schedule the initial processing of the message queue.
128
- * JS engine-specific microtask mechanism is used in order to boost performance on short runs and a dispatch batch
129
- * 2) [reschedule] is used to schedule processing of the queue after yield to the JS event loop.
130
- * JS engine-specific macrotask mechanism is used not to starve animations and non-coroutines macrotasks.
131
- *
132
- * Yet there could be a long tail of "slow" reschedules, but it should be amortized by the queue size.
133
- */
134
- internal abstract class MessageQueue : MutableList <Runnable > by ArrayDeque () {
135
- val yieldEvery = 16 // yield to JS macrotask event loop after this many processed messages
136
- private var scheduled = false
137
-
138
- abstract fun schedule ()
139
-
140
- abstract fun reschedule ()
141
-
142
- fun enqueue (element : Runnable ) {
143
- add(element)
144
- if (! scheduled) {
145
- scheduled = true
146
- schedule()
147
- }
148
- }
149
-
150
- fun process () {
151
- try {
152
- // limit number of processed messages
153
- repeat(yieldEvery) {
154
- val element = removeFirstOrNull() ? : return @process
155
- element.run ()
156
- }
157
- } finally {
158
- if (isEmpty()) {
159
- scheduled = false
160
- } else {
161
- reschedule()
162
- }
163
- }
164
- }
165
- }
166
-
167
49
// We need to reference global setTimeout and clearTimeout so that it works on Node.JS as opposed to
168
50
// using them via "window" (which only works in browser)
169
- private external fun setTimeout (handler : dynamic , timeout : Int = definedExternally): Int
170
- private external fun clearTimeout (handle : Int = definedExternally)
51
+ internal external fun setTimeout (handler : dynamic , timeout : Int = definedExternally): Int
52
+ internal external fun clearTimeout (handle : Int = definedExternally)
53
+ internal fun setTimeout (window : WindowOrWorkerGlobalScope , handler : () -> Unit , timeout : Int ): Int =
54
+ window.setTimeout(handler, timeout)
0 commit comments