@@ -10,6 +10,42 @@ exports.setup = setupNextTick;
1010// Will be overwritten when setupNextTick() is called.
1111exports . nextTick = null ;
1212
13+ class NextTickQueue {
14+ constructor ( ) {
15+ this . head = null ;
16+ this . tail = null ;
17+ this . length = 0 ;
18+ }
19+
20+ push ( v ) {
21+ const entry = { data : v , next : null } ;
22+ if ( this . length > 0 )
23+ this . tail . next = entry ;
24+ else
25+ this . head = entry ;
26+ this . tail = entry ;
27+ ++ this . length ;
28+ }
29+
30+ shift ( ) {
31+ if ( this . length === 0 )
32+ return ;
33+ const ret = this . head . data ;
34+ if ( this . length === 1 )
35+ this . head = this . tail = null ;
36+ else
37+ this . head = this . head . next ;
38+ -- this . length ;
39+ return ret ;
40+ }
41+
42+ clear ( ) {
43+ this . head = null ;
44+ this . tail = null ;
45+ this . length = 0 ;
46+ }
47+ }
48+
1349function setupNextTick ( ) {
1450 const async_wrap = process . binding ( 'async_wrap' ) ;
1551 const async_hooks = require ( 'async_hooks' ) ;
@@ -27,7 +63,7 @@ function setupNextTick() {
2763 const { kInit, kBefore, kAfter, kDestroy, kAsyncUidCntr, kInitTriggerId } =
2864 async_wrap . constants ;
2965 const { async_id_symbol, trigger_id_symbol } = async_wrap ;
30- var nextTickQueue = [ ] ;
66+ var nextTickQueue = new NextTickQueue ( ) ;
3167 var microtasksScheduled = false ;
3268
3369 // Used to run V8's micro task queue.
@@ -55,27 +91,29 @@ function setupNextTick() {
5591 function tickDone ( ) {
5692 if ( tickInfo [ kLength ] !== 0 ) {
5793 if ( tickInfo [ kLength ] <= tickInfo [ kIndex ] ) {
58- nextTickQueue = [ ] ;
94+ nextTickQueue . clear ( ) ;
5995 tickInfo [ kLength ] = 0 ;
6096 } else {
61- nextTickQueue . splice ( 0 , tickInfo [ kIndex ] ) ;
6297 tickInfo [ kLength ] = nextTickQueue . length ;
6398 }
6499 }
65100 tickInfo [ kIndex ] = 0 ;
66101 }
67102
103+ const microTasksTickObject = {
104+ callback : runMicrotasksCallback ,
105+ args : undefined ,
106+ domain : null ,
107+ [ async_id_symbol ] : 0 ,
108+ [ trigger_id_symbol ] : 0
109+ } ;
68110 function scheduleMicrotasks ( ) {
69111 if ( microtasksScheduled )
70112 return ;
71113
72- const tickObject =
73- new TickObject ( runMicrotasksCallback , undefined , null ) ;
74114 // For the moment all microtasks come from the void until the PromiseHook
75115 // API is implemented.
76- tickObject [ async_id_symbol ] = 0 ;
77- tickObject [ trigger_id_symbol ] = 0 ;
78- nextTickQueue . push ( tickObject ) ;
116+ nextTickQueue . push ( microTasksTickObject ) ;
79117
80118 tickInfo [ kLength ] ++ ;
81119 microtasksScheduled = true ;
@@ -86,8 +124,9 @@ function setupNextTick() {
86124 _runMicrotasks ( ) ;
87125
88126 if ( tickInfo [ kIndex ] < tickInfo [ kLength ] ||
89- emitPendingUnhandledRejections ( ) )
127+ emitPendingUnhandledRejections ( ) ) {
90128 scheduleMicrotasks ( ) ;
129+ }
91130 }
92131
93132 function _combinedTickCallback ( args , callback ) {
@@ -133,7 +172,8 @@ function setupNextTick() {
133172 function _tickCallback ( ) {
134173 do {
135174 while ( tickInfo [ kIndex ] < tickInfo [ kLength ] ) {
136- const tock = nextTickQueue [ tickInfo [ kIndex ] ++ ] ;
175+ ++ tickInfo [ kIndex ] ;
176+ const tock = nextTickQueue . shift ( ) ;
137177 const callback = tock . callback ;
138178 const args = tock . args ;
139179
@@ -174,7 +214,8 @@ function setupNextTick() {
174214 function _tickDomainCallback ( ) {
175215 do {
176216 while ( tickInfo [ kIndex ] < tickInfo [ kLength ] ) {
177- const tock = nextTickQueue [ tickInfo [ kIndex ] ++ ] ;
217+ ++ tickInfo [ kIndex ] ;
218+ const tock = nextTickQueue . shift ( ) ;
178219 const callback = tock . callback ;
179220 const domain = tock . domain ;
180221 const args = tock . args ;
@@ -210,45 +251,48 @@ function setupNextTick() {
210251 } while ( tickInfo [ kLength ] !== 0 ) ;
211252 }
212253
213- function TickObject ( callback , args , domain ) {
214- this . callback = callback ;
215- this . domain = domain ;
216- this . args = args ;
217- this [ async_id_symbol ] = - 1 ;
218- this [ trigger_id_symbol ] = - 1 ;
219- }
220-
221- function setupInit ( tickObject , triggerAsyncId ) {
222- tickObject [ async_id_symbol ] = ++ async_uid_fields [ kAsyncUidCntr ] ;
223- tickObject [ trigger_id_symbol ] = triggerAsyncId || initTriggerId ( ) ;
224- if ( async_hook_fields [ kInit ] > 0 ) {
225- emitInit ( tickObject [ async_id_symbol ] ,
226- 'TickObject' ,
227- tickObject [ trigger_id_symbol ] ,
228- tickObject ) ;
254+ class TickObject {
255+ constructor ( callback , args , asyncId , triggerAsyncId ) {
256+ this . callback = callback ;
257+ this . args = args ;
258+ this . domain = process . domain || null ;
259+ this [ async_id_symbol ] = asyncId ;
260+ this [ trigger_id_symbol ] = triggerAsyncId ;
229261 }
230262 }
231263
264+ // `nextTick()` will not enqueue any callback when the process is about to
265+ // exit since the callback would not have a chance to be executed.
232266 function nextTick ( callback ) {
233267 if ( typeof callback !== 'function' )
234268 throw new errors . TypeError ( 'ERR_INVALID_CALLBACK' ) ;
235- // on the way out, don't bother. it won't get fired anyway.
269+
236270 if ( process . _exiting )
237271 return ;
238272
239273 var args ;
240- if ( arguments . length > 1 ) {
241- args = new Array ( arguments . length - 1 ) ;
242- for ( var i = 1 ; i < arguments . length ; i ++ )
243- args [ i - 1 ] = arguments [ i ] ;
274+ switch ( arguments . length ) {
275+ case 1 : break ;
276+ case 2 : args = [ arguments [ 1 ] ] ; break ;
277+ case 3 : args = [ arguments [ 1 ] , arguments [ 2 ] ] ; break ;
278+ case 4 : args = [ arguments [ 1 ] , arguments [ 2 ] , arguments [ 3 ] ] ; break ;
279+ default :
280+ args = new Array ( arguments . length - 1 ) ;
281+ for ( var i = 1 ; i < arguments . length ; i ++ )
282+ args [ i - 1 ] = arguments [ i ] ;
244283 }
245284
246- var obj = new TickObject ( callback , args , process . domain || null ) ;
247- setupInit ( obj , null ) ;
285+ const asyncId = ++ async_uid_fields [ kAsyncUidCntr ] ;
286+ const triggerAsyncId = initTriggerId ( ) ;
287+ const obj = new TickObject ( callback , args , asyncId , triggerAsyncId ) ;
248288 nextTickQueue . push ( obj ) ;
249- tickInfo [ kLength ] ++ ;
289+ ++ tickInfo [ kLength ] ;
290+ if ( async_hook_fields [ kInit ] > 0 )
291+ emitInit ( asyncId , 'TickObject' , triggerAsyncId , obj ) ;
250292 }
251293
294+ // `internalNextTick()` will not enqueue any callback when the process is
295+ // about to exit since the callback would not have a chance to be executed.
252296 function internalNextTick ( triggerAsyncId , callback ) {
253297 if ( typeof callback !== 'function' )
254298 throw new TypeError ( 'callback is not a function' ) ;
@@ -259,17 +303,25 @@ function setupNextTick() {
259303 return ;
260304
261305 var args ;
262- if ( arguments . length > 2 ) {
263- args = new Array ( arguments . length - 2 ) ;
264- for ( var i = 2 ; i < arguments . length ; i ++ )
265- args [ i - 2 ] = arguments [ i ] ;
306+ switch ( arguments . length ) {
307+ case 2 : break ;
308+ case 3 : args = [ arguments [ 2 ] ] ; break ;
309+ case 4 : args = [ arguments [ 2 ] , arguments [ 3 ] ] ; break ;
310+ case 5 : args = [ arguments [ 2 ] , arguments [ 3 ] , arguments [ 4 ] ] ; break ;
311+ default :
312+ args = new Array ( arguments . length - 2 ) ;
313+ for ( var i = 2 ; i < arguments . length ; i ++ )
314+ args [ i - 2 ] = arguments [ i ] ;
266315 }
267316
268- var obj = new TickObject ( callback , args , process . domain || null ) ;
269- setupInit ( obj , triggerAsyncId ) ;
317+ const asyncId = ++ async_uid_fields [ kAsyncUidCntr ] ;
318+ const obj = new TickObject ( callback , args , asyncId , triggerAsyncId ) ;
319+ nextTickQueue . push ( obj ) ;
320+ ++ tickInfo [ kLength ] ;
321+ if ( async_hook_fields [ kInit ] > 0 )
322+ emitInit ( asyncId , 'TickObject' , triggerAsyncId , obj ) ;
323+
270324 // The call to initTriggerId() was skipped, so clear kInitTriggerId.
271325 async_uid_fields [ kInitTriggerId ] = 0 ;
272- nextTickQueue . push ( obj ) ;
273- tickInfo [ kLength ] ++ ;
274326 }
275327}
0 commit comments