@@ -10,6 +10,42 @@ exports.setup = setupNextTick;
10
10
// Will be overwritten when setupNextTick() is called.
11
11
exports . nextTick = null ;
12
12
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
+
13
49
function setupNextTick ( ) {
14
50
const async_wrap = process . binding ( 'async_wrap' ) ;
15
51
const async_hooks = require ( 'async_hooks' ) ;
@@ -27,7 +63,7 @@ function setupNextTick() {
27
63
const { kInit, kBefore, kAfter, kDestroy, kAsyncUidCntr, kInitTriggerId } =
28
64
async_wrap . constants ;
29
65
const { async_id_symbol, trigger_id_symbol } = async_wrap ;
30
- var nextTickQueue = [ ] ;
66
+ var nextTickQueue = new NextTickQueue ( ) ;
31
67
var microtasksScheduled = false ;
32
68
33
69
// Used to run V8's micro task queue.
@@ -55,27 +91,29 @@ function setupNextTick() {
55
91
function tickDone ( ) {
56
92
if ( tickInfo [ kLength ] !== 0 ) {
57
93
if ( tickInfo [ kLength ] <= tickInfo [ kIndex ] ) {
58
- nextTickQueue = [ ] ;
94
+ nextTickQueue . clear ( ) ;
59
95
tickInfo [ kLength ] = 0 ;
60
96
} else {
61
- nextTickQueue . splice ( 0 , tickInfo [ kIndex ] ) ;
62
97
tickInfo [ kLength ] = nextTickQueue . length ;
63
98
}
64
99
}
65
100
tickInfo [ kIndex ] = 0 ;
66
101
}
67
102
103
+ const microTasksTickObject = {
104
+ callback : runMicrotasksCallback ,
105
+ args : undefined ,
106
+ domain : null ,
107
+ [ async_id_symbol ] : 0 ,
108
+ [ trigger_id_symbol ] : 0
109
+ } ;
68
110
function scheduleMicrotasks ( ) {
69
111
if ( microtasksScheduled )
70
112
return ;
71
113
72
- const tickObject =
73
- new TickObject ( runMicrotasksCallback , undefined , null ) ;
74
114
// For the moment all microtasks come from the void until the PromiseHook
75
115
// API is implemented.
76
- tickObject [ async_id_symbol ] = 0 ;
77
- tickObject [ trigger_id_symbol ] = 0 ;
78
- nextTickQueue . push ( tickObject ) ;
116
+ nextTickQueue . push ( microTasksTickObject ) ;
79
117
80
118
tickInfo [ kLength ] ++ ;
81
119
microtasksScheduled = true ;
@@ -86,8 +124,9 @@ function setupNextTick() {
86
124
_runMicrotasks ( ) ;
87
125
88
126
if ( tickInfo [ kIndex ] < tickInfo [ kLength ] ||
89
- emitPendingUnhandledRejections ( ) )
127
+ emitPendingUnhandledRejections ( ) ) {
90
128
scheduleMicrotasks ( ) ;
129
+ }
91
130
}
92
131
93
132
function _combinedTickCallback ( args , callback ) {
@@ -133,7 +172,8 @@ function setupNextTick() {
133
172
function _tickCallback ( ) {
134
173
do {
135
174
while ( tickInfo [ kIndex ] < tickInfo [ kLength ] ) {
136
- const tock = nextTickQueue [ tickInfo [ kIndex ] ++ ] ;
175
+ ++ tickInfo [ kIndex ] ;
176
+ const tock = nextTickQueue . shift ( ) ;
137
177
const callback = tock . callback ;
138
178
const args = tock . args ;
139
179
@@ -174,7 +214,8 @@ function setupNextTick() {
174
214
function _tickDomainCallback ( ) {
175
215
do {
176
216
while ( tickInfo [ kIndex ] < tickInfo [ kLength ] ) {
177
- const tock = nextTickQueue [ tickInfo [ kIndex ] ++ ] ;
217
+ ++ tickInfo [ kIndex ] ;
218
+ const tock = nextTickQueue . shift ( ) ;
178
219
const callback = tock . callback ;
179
220
const domain = tock . domain ;
180
221
const args = tock . args ;
@@ -210,45 +251,48 @@ function setupNextTick() {
210
251
} while ( tickInfo [ kLength ] !== 0 ) ;
211
252
}
212
253
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 ;
229
261
}
230
262
}
231
263
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.
232
266
function nextTick ( callback ) {
233
267
if ( typeof callback !== 'function' )
234
268
throw new errors . TypeError ( 'ERR_INVALID_CALLBACK' ) ;
235
- // on the way out, don't bother. it won't get fired anyway.
269
+
236
270
if ( process . _exiting )
237
271
return ;
238
272
239
273
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 ] ;
244
283
}
245
284
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 ) ;
248
288
nextTickQueue . push ( obj ) ;
249
- tickInfo [ kLength ] ++ ;
289
+ ++ tickInfo [ kLength ] ;
290
+ if ( async_hook_fields [ kInit ] > 0 )
291
+ emitInit ( asyncId , 'TickObject' , triggerAsyncId , obj ) ;
250
292
}
251
293
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.
252
296
function internalNextTick ( triggerAsyncId , callback ) {
253
297
if ( typeof callback !== 'function' )
254
298
throw new TypeError ( 'callback is not a function' ) ;
@@ -259,17 +303,25 @@ function setupNextTick() {
259
303
return ;
260
304
261
305
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 ] ;
266
315
}
267
316
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
+
270
324
// The call to initTriggerId() was skipped, so clear kInitTriggerId.
271
325
async_uid_fields [ kInitTriggerId ] = 0 ;
272
- nextTickQueue . push ( obj ) ;
273
- tickInfo [ kLength ] ++ ;
274
326
}
275
327
}
0 commit comments