@@ -31,10 +31,60 @@ function setupNextTick() {
3131 const kHasScheduled = 0 ;
3232 const kHasPromiseRejections = 1 ;
3333
34- // Queue size for each tick array. Must be a factor of two.
34+ // Queue size for each tick array. Must be a power of two.
3535 const kQueueSize = 2048 ;
3636 const kQueueMask = kQueueSize - 1 ;
3737
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+
3888 class FixedQueue {
3989 constructor ( ) {
4090 this . bottom = 0 ;
@@ -49,11 +99,12 @@ function setupNextTick() {
4999 }
50100
51101 shift ( ) {
52- const next = this . list [ this . bottom ] ;
53- if ( next === undefined ) return null ;
102+ const nextItem = this . list [ this . bottom ] ;
103+ if ( nextItem === undefined )
104+ return null ;
54105 this . list [ this . bottom ] = undefined ;
55106 this . bottom = ( this . bottom + 1 ) & kQueueMask ;
56- return next ;
107+ return nextItem ;
57108 }
58109 }
59110
@@ -62,21 +113,34 @@ function setupNextTick() {
62113
63114 function push ( data ) {
64115 if ( head . bottom === head . top ) {
65- if ( head . list [ head . top ] !== undefined )
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.
66120 head = head . next = new FixedQueue ( ) ;
67- else
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()`.
68127 tickInfo [ kHasScheduled ] = 1 ;
128+ }
69129 }
70130 head . push ( data ) ;
71131 }
72132
73133 function shift ( ) {
74134 const next = tail . shift ( ) ;
75- if ( tail . top === tail . bottom ) {
76- if ( tail . next )
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.
77138 tail = tail . next ;
78- else
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.
79142 tickInfo [ kHasScheduled ] = 0 ;
143+ }
80144 }
81145 return next ;
82146 }
0 commit comments