@@ -16,6 +16,7 @@ function setupNextTick() {
1616 } = require ( 'internal/async_hooks' ) ;
1717 const promises = require ( 'internal/process/promises' ) ;
1818 const { ERR_INVALID_CALLBACK } = require ( 'internal/errors' ) . codes ;
19+ const FixedQueue = require ( 'internal/fixed_queue' ) ;
1920 const { emitPromiseRejectionWarnings } = promises ;
2021
2122 // tickInfo is used so that the C++ code in src/node.cc can
@@ -31,119 +32,7 @@ function setupNextTick() {
3132 const kHasScheduled = 0 ;
3233 const kHasPromiseRejections = 1 ;
3334
34- // Queue size for each tick array. Must be a power of two.
35- const kQueueSize = 2048 ;
36- const kQueueMask = kQueueSize - 1 ;
37-
38- // The next tick queue is implemented as a singly-linked list of fixed-size
39- // circular buffers. It looks something like this:
40- //
41- // head tail
42- // | |
43- // v v
44- // +-----------+ <-----\ +-----------+ <------\ +-----------+
45- // | [null] | \----- | next | \------- | next |
46- // +-----------+ +-----------+ +-----------+
47- // | tick | <-- bottom | tick | <-- bottom | [empty] |
48- // | tick | | tick | | [empty] |
49- // | tick | | tick | | [empty] |
50- // | tick | | tick | | [empty] |
51- // | tick | | tick | bottom --> | tick |
52- // | tick | | tick | | tick |
53- // | ... | | ... | | ... |
54- // | tick | | tick | | tick |
55- // | tick | | tick | | tick |
56- // | [empty] | <-- top | tick | | tick |
57- // | [empty] | | tick | | tick |
58- // | [empty] | | tick | | tick |
59- // +-----------+ +-----------+ <-- top top --> +-----------+
60- //
61- // Or, if there is only one fixed-size queue, it looks something
62- // like either of these:
63- //
64- // head tail head tail
65- // | | | |
66- // v v v v
67- // +-----------+ +-----------+
68- // | [null] | | [null] |
69- // +-----------+ +-----------+
70- // | [empty] | | tick |
71- // | [empty] | | tick |
72- // | tick | <-- bottom top --> | [empty] |
73- // | tick | | [empty] |
74- // | [empty] | <-- top bottom --> | tick |
75- // | [empty] | | tick |
76- // +-----------+ +-----------+
77- //
78- // Adding a value means moving `top` forward by one, removing means
79- // moving `bottom` forward by one.
80- //
81- // We let `bottom` and `top` wrap around, so when `top` is conceptually
82- // pointing to the end of the list, that means that the actual value is `0`.
83- //
84- // In particular, when `top === bottom`, this can mean *either* that the
85- // current queue is empty or that it is full. We can differentiate by
86- // checking whether an entry in the queue is empty (a.k.a. `=== undefined`).
87-
88- class FixedQueue {
89- constructor ( ) {
90- this . bottom = 0 ;
91- this . top = 0 ;
92- this . list = new Array ( kQueueSize ) ;
93- this . next = null ;
94- }
95-
96- push ( data ) {
97- this . list [ this . top ] = data ;
98- this . top = ( this . top + 1 ) & kQueueMask ;
99- }
100-
101- shift ( ) {
102- const nextItem = this . list [ this . bottom ] ;
103- if ( nextItem === undefined )
104- return null ;
105- this . list [ this . bottom ] = undefined ;
106- this . bottom = ( this . bottom + 1 ) & kQueueMask ;
107- return nextItem ;
108- }
109- }
110-
111- var head = new FixedQueue ( ) ;
112- var tail = head ;
113-
114- function push ( data ) {
115- if ( head . bottom === head . top ) {
116- // Either empty or full:
117- if ( head . list [ head . top ] !== undefined ) {
118- // It's full: Creates a new queue, sets the old queue's `.next` to it,
119- // and sets it as the new main queue.
120- head = head . next = new FixedQueue ( ) ;
121- } else {
122- // If the head is empty, that means that it was the only fixed-sized
123- // queue in existence.
124- DCHECK_EQ ( head . next , null ) ;
125- // This is the first tick object in existence, so we need to inform
126- // the C++ side that we do want to run `_tickCallback()`.
127- tickInfo [ kHasScheduled ] = 1 ;
128- }
129- }
130- head . push ( data ) ;
131- }
132-
133- function shift ( ) {
134- const next = tail . shift ( ) ;
135- if ( tail . top === tail . bottom ) { // -> .shift() emptied the current queue.
136- if ( tail . next !== null ) {
137- // If there is another queue, it forms the new tail.
138- tail = tail . next ;
139- } else {
140- // We've just run out of items. Let the native side know that it
141- // doesn't need to bother calling into JS to run the queue.
142- tickInfo [ kHasScheduled ] = 0 ;
143- }
144- }
145- return next ;
146- }
35+ const queue = new FixedQueue ( ) ;
14736
14837 process . nextTick = nextTick ;
14938 // Needs to be accessible from beyond this scope.
@@ -152,7 +41,7 @@ function setupNextTick() {
15241 function _tickCallback ( ) {
15342 let tock ;
15443 do {
155- while ( tock = shift ( ) ) {
44+ while ( tock = queue . shift ( ) ) {
15645 const asyncId = tock [ async_id_symbol ] ;
15746 emitBefore ( asyncId , tock [ trigger_async_id_symbol ] ) ;
15847 // emitDestroy() places the async_id_symbol into an asynchronous queue
@@ -175,8 +64,9 @@ function setupNextTick() {
17564
17665 emitAfter ( asyncId ) ;
17766 }
67+ tickInfo [ kHasScheduled ] = 0 ;
17868 runMicrotasks ( ) ;
179- } while ( head . top !== head . bottom || emitPromiseRejectionWarnings ( ) ) ;
69+ } while ( ! queue . isEmpty ( ) || emitPromiseRejectionWarnings ( ) ) ;
18070 tickInfo [ kHasPromiseRejections ] = 0 ;
18171 }
18272
@@ -222,6 +112,8 @@ function setupNextTick() {
222112 args [ i - 1 ] = arguments [ i ] ;
223113 }
224114
225- push ( new TickObject ( callback , args , getDefaultTriggerAsyncId ( ) ) ) ;
115+ if ( queue . isEmpty ( ) )
116+ tickInfo [ kHasScheduled ] = 1 ;
117+ queue . push ( new TickObject ( callback , args , getDefaultTriggerAsyncId ( ) ) ) ;
226118 }
227119}
0 commit comments