@@ -23,91 +23,57 @@ export function install() {
2323
2424export function runPendingImmediatesAfterCurrentTask ( ) {
2525 startCapturingImmediates ( )
26+ scheduleWorkAfterTicksAndMicrotasks ( )
27+ }
2628
27- const scheduleWorkAfterTicksAndMicrotasks = ( ) => {
28- originalNextTick ( ( ) => {
29- queueMicrotask ( ( ) => {
30- originalNextTick ( ( ) => {
31- if ( pendingNextTicks > 0 ) {
32- // We have raw nextTicks. Let those run first.
33- debug ?.( `scheduler :: yielding to ${ pendingNextTicks } nextTicks` )
34- return scheduleWorkAfterTicksAndMicrotasks ( )
35- }
36-
37- return performWork ( )
38- } )
29+ function scheduleWorkAfterTicksAndMicrotasks ( ) {
30+ originalNextTick ( ( ) => {
31+ queueMicrotask ( ( ) => {
32+ originalNextTick ( ( ) => {
33+ if ( pendingNextTicks > 0 ) {
34+ // We have raw nextTicks. Let those run first.
35+ debug ?.( `scheduler :: yielding to ${ pendingNextTicks } nextTicks` )
36+ return scheduleWorkAfterTicksAndMicrotasks ( )
37+ }
38+
39+ return performWork ( )
3940 } )
4041 } )
41- }
42+ } )
43+ }
4244
43- const performWork = ( ) => {
44- debug ?.( `scheduler :: performing work` )
45+ function performWork ( ) {
46+ debug ?.( `scheduler :: performing work` )
4547
46- // Find the first (if any) queued immediate that wasn't cleared
47- let queueItem : ActiveQueueItem | null = null
48- while ( queuedImmediates . length ) {
49- const maybeQueItem = queuedImmediates . shift ( ) !
50- if ( ! maybeQueItem . isCleared ) {
51- queueItem = maybeQueItem
52- break
53- }
54- }
55- if ( ! queueItem ) {
56- debug ?.( `scheduler :: no immediates queued, exiting` )
57- stopCapturingImmediates ( )
58- return
48+ // Find the first (if any) queued immediate that wasn't cleared
49+ let queueItem : ActiveQueueItem | null = null
50+ while ( queuedImmediates . length ) {
51+ const maybeQueItem = queuedImmediates . shift ( ) !
52+ if ( ! maybeQueItem . isCleared ) {
53+ queueItem = maybeQueItem
54+ break
5955 }
60-
61- const { immediateObject, callback, args } = queueItem
62-
63- // note that this is not a real Immediate object, because we're running them in a nextTick
64- // TODO: we're already in our own tick, do we need another one?
65- const handle = args
66- ? scheduleImmediateInNextTickAndContinueLoop ( callback , ...args )
67- : scheduleImmediateInNextTickAndContinueLoop ( callback )
68-
69- // Now that we're no longer buffering the immediate,
70- // make the BufferedImmediate proxy calls to the native object instead
71- immediateObject [ INTERNALS ] . queueItem = null
72- immediateObject [ INTERNALS ] . nativeImmediate = handle
73- clearQueueItem ( queueItem )
56+ }
57+ if ( ! queueItem ) {
58+ debug ?.( `scheduler :: no immediates queued, exiting` )
59+ stopCapturingImmediates ( )
60+ return
7461 }
7562
76- const scheduleImmediateInNextTickAndContinueLoop = (
77- callback : ( ...args : any [ ] ) => any ,
78- ...args : any [ ]
79- ) => {
80- let isCleared = false
63+ const { immediateObject, callback, args } = queueItem
8164
82- originalNextTick ( ( ) => {
83- // schedule the loop again in case there's more immediates after this.
84- scheduleWorkAfterTicksAndMicrotasks ( )
65+ immediateObject [ INTERNALS ] . queueItem = null
66+ clearQueueItem ( queueItem )
8567
86- if ( isCleared ) return
87- callback . apply ( null , args )
88- } )
68+ // schedule the loop again in case there's more immediates after this.
69+ scheduleWorkAfterTicksAndMicrotasks ( )
8970
90- const handle = {
91- ref ( ) {
92- return this
93- } ,
94- unref ( ) {
95- return this
96- } ,
97- hasRef ( ) {
98- return true
99- } ,
100- _onImmediate ( ) { } ,
101-
102- [ Symbol . dispose ] ( ) {
103- isCleared = true
104- } ,
105- } satisfies NodeJS . Immediate
106-
107- return handle
71+ // execute the callback.
72+ if ( args ) {
73+ callback . apply ( null , args )
74+ } else {
75+ callback ( )
10876 }
109-
110- scheduleWorkAfterTicksAndMicrotasks ( )
11177}
11278
11379function startCapturingImmediates ( ) {
@@ -132,14 +98,12 @@ type ActiveQueueItem = {
13298 isCleared : false
13399 callback : ( ...args : any [ ] ) => any
134100 args : any [ ] | null
135- hasRef : boolean
136- immediateObject : BufferedImmediate
101+ immediateObject : NextImmediate
137102}
138103type ClearedQueueItem = {
139104 isCleared : true
140105 callback : null
141106 args : null
142- hasRef : null
143107 immediateObject : null
144108}
145109
@@ -148,7 +112,6 @@ function clearQueueItem(originalQueueItem: QueueItem) {
148112 queueItem . isCleared = true
149113 queueItem . callback = null
150114 queueItem . args = null
151- queueItem . hasRef = null
152115 queueItem . immediateObject = null
153116}
154117
@@ -220,13 +183,12 @@ function patchedSetImmediate(): NodeJS.Immediate {
220183 let args : any [ ] | null =
221184 arguments . length > 1 ? Array . prototype . slice . call ( arguments , 1 ) : null
222185
223- const immediateObject = new BufferedImmediate ( )
186+ const immediateObject = new NextImmediate ( )
224187
225188 const queueItem : ActiveQueueItem = {
226189 isCleared : false ,
227190 callback,
228191 args,
229- hasRef : true ,
230192 immediateObject,
231193 }
232194 queuedImmediates . push ( queueItem )
@@ -256,9 +218,9 @@ function patchedSetImmediatePromisify<T = void>(
256218 }
257219
258220 const immediate = patchedSetImmediate ( resolve , value )
259- if ( options ?. ref === false ) {
260- immediate . unref ( )
261- }
221+
222+ // Note that we're ignoring `options.ref`, because ` unref()` has no effect
223+ // on our patched immediates
262224
263225 if ( signal ) {
264226 signal . addEventListener (
@@ -279,7 +241,7 @@ const patchedClearImmediate = (
279241 immediateObject : NodeJS . Immediate | undefined
280242) => {
281243 if ( immediateObject && INTERNALS in immediateObject ) {
282- ; ( immediateObject as BufferedImmediate ) [ Symbol . dispose ] ( )
244+ ; ( immediateObject as NextImmediate ) [ Symbol . dispose ] ( )
283245 } else {
284246 originalClearImmediate ( immediateObject )
285247 }
@@ -289,50 +251,41 @@ const patchedClearImmediate = (
289251
290252const INTERNALS : unique symbol = Symbol . for ( 'next.Immediate.internals' )
291253
292- type QueuedImmediateInternals =
293- | {
294- queueItem : ActiveQueueItem | null
295- nativeImmediate : null
296- }
297- | {
298- queueItem : null
299- nativeImmediate : NodeJS . Immediate
300- }
254+ type NextImmediateInternals = {
255+ /** Stored to reflect `ref()`/`unref()` calls, but has no effect otherwise */
256+ hasRef : boolean
257+ queueItem : ActiveQueueItem | null
258+ }
301259
302260/** Makes sure that we're implementing all the public `Immediate` methods */
303261interface NativeImmediate extends NodeJS . Immediate { }
304262
305263/** Implements a shim for the native `Immediate` class returned by `setImmediate` */
306- class BufferedImmediate implements NativeImmediate {
307- [ INTERNALS ] : QueuedImmediateInternals = {
264+ class NextImmediate implements NativeImmediate {
265+ [ INTERNALS ] : NextImmediateInternals = {
308266 queueItem : null ,
309- nativeImmediate : null ,
267+ hasRef : true ,
310268 }
311269 hasRef ( ) {
312270 const internals = this [ INTERNALS ]
313271 if ( internals . queueItem ) {
314- return internals . queueItem . hasRef
315- } else if ( internals . nativeImmediate ) {
316- return internals . nativeImmediate . hasRef ( )
272+ return internals . hasRef
317273 } else {
274+ // if we're no longer queued (cleared or executed), hasRef is always false
318275 return false
319276 }
320277 }
321278 ref ( ) {
322279 const internals = this [ INTERNALS ]
323280 if ( internals . queueItem ) {
324- internals . queueItem . hasRef = true
325- } else if ( internals . nativeImmediate ) {
326- internals . nativeImmediate . ref ( )
281+ internals . hasRef = true
327282 }
328283 return this
329284 }
330285 unref ( ) {
331286 const internals = this [ INTERNALS ]
332287 if ( internals . queueItem ) {
333- internals . queueItem . hasRef = false
334- } else if ( internals . nativeImmediate ) {
335- internals . nativeImmediate . unref ( )
288+ internals . hasRef = false
336289 }
337290 return this
338291 }
@@ -348,9 +301,6 @@ class BufferedImmediate implements NativeImmediate {
348301 const queueItem = internals . queueItem
349302 internals . queueItem = null
350303 clearQueueItem ( queueItem )
351- } else if ( internals . nativeImmediate ) {
352- // If we executed the queue, and we have a native immediate.
353- originalClearImmediate ( internals . nativeImmediate )
354304 }
355305 }
356306}
0 commit comments