@@ -7,34 +7,71 @@ package kotlinx.coroutines
77import kotlinx.coroutines.internal.*
88import org.w3c.dom.*
99import kotlin.coroutines.*
10- import kotlin.js.*
10+ import kotlin.js.Promise
1111
1212private const val MAX_DELAY = Int .MAX_VALUE .toLong()
1313
1414private fun delayToInt (timeMillis : Long ): Int =
1515 timeMillis.coerceIn(0 , MAX_DELAY ).toInt()
1616
17- internal object NodeDispatcher : CoroutineDispatcher(), Delay {
18- override fun dispatch (context : CoroutineContext , block : Runnable ) = NodeJsMessageQueue .enqueue(block)
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 dispatch (context : CoroutineContext , block : Runnable ) {
35+ messageQueue.enqueue(block)
36+ }
37+
38+ override fun invokeOnTimeout (timeMillis : Long , block : Runnable ): DisposableHandle {
39+ val handle = setTimeout({ block.run () }, delayToInt(timeMillis))
40+ return ClearTimeout (handle)
41+ }
1942
2043 override fun scheduleResumeAfterDelay (timeMillis : Long , continuation : CancellableContinuation <Unit >) {
2144 val handle = setTimeout({ with (continuation) { resumeUndispatched(Unit ) } }, delayToInt(timeMillis))
2245 // Actually on cancellation, but clearTimeout is idempotent
2346 continuation.invokeOnCancellation(handler = ClearTimeout (handle).asHandler)
2447 }
48+ }
2549
26- private class ClearTimeout (private val handle : Int ) : CancelHandler(), DisposableHandle {
27- override fun dispose () { clearTimeout(handle) }
28- override fun invoke (cause : Throwable ? ) { dispose() }
29- override fun toString (): String = " ClearTimeout[$handle ]"
50+ internal object NodeDispatcher : SetTimeoutBasedDispatcher() {
51+ override fun scheduleQueueProcessing () {
52+ process.nextTick(messageQueue.processQueue)
3053 }
54+ }
3155
32- override fun invokeOnTimeout ( timeMillis : Long , block : Runnable ): DisposableHandle {
33- val handle = setTimeout({ block. run () }, delayToInt(timeMillis))
34- return ClearTimeout (handle )
56+ internal object SetTimeoutDispatcher : SetTimeoutBasedDispatcher() {
57+ override fun scheduleQueueProcessing () {
58+ setTimeout(messageQueue.processQueue, 0 )
3559 }
3660}
3761
62+ private class ClearTimeout (private val handle : Int ) : CancelHandler(), DisposableHandle {
63+
64+ override fun dispose () {
65+ clearTimeout(handle)
66+ }
67+
68+ override fun invoke (cause : Throwable ? ) {
69+ dispose()
70+ }
71+
72+ override fun toString (): String = " ClearTimeout[$handle ]"
73+ }
74+
3875internal class WindowDispatcher (private val window : Window ) : CoroutineDispatcher(), Delay {
3976 private val queue = WindowMessageQueue (window)
4077
@@ -75,17 +112,6 @@ private class WindowMessageQueue(private val window: Window) : MessageQueue() {
75112 }
76113}
77114
78- private object NodeJsMessageQueue : MessageQueue() {
79- override fun schedule () {
80- // next tick is even faster than resolve
81- process.nextTick({ process() })
82- }
83-
84- override fun reschedule () {
85- setTimeout({ process() }, 0 )
86- }
87- }
88-
89115/* *
90116 * An abstraction over JS scheduling mechanism that leverages micro-batching of [dispatch] blocks without
91117 * paying the cost of JS callbacks scheduling on every dispatch.
@@ -100,9 +126,8 @@ private object NodeJsMessageQueue : MessageQueue() {
100126 */
101127internal abstract class MessageQueue : ArrayQueue <Runnable >() {
102128 val yieldEvery = 16 // yield to JS macrotask event loop after this many processed messages
103-
104129 private var scheduled = false
105-
130+
106131 abstract fun schedule ()
107132
108133 abstract fun reschedule ()
@@ -136,4 +161,3 @@ internal abstract class MessageQueue : ArrayQueue<Runnable>() {
136161// using them via "window" (which only works in browser)
137162private external fun setTimeout (handler : dynamic , timeout : Int = definedExternally): Int
138163private external fun clearTimeout (handle : Int = definedExternally)
139- private external val process: dynamic
0 commit comments