@@ -32,10 +32,60 @@ function setupNextTick() {
3232 const kHasScheduled = 0 ;
3333 const kHasPromiseRejections = 1 ;
3434
35- // Queue size for each tick array. Must be a factor of two.
35+ // Queue size for each tick array. Must be a power of two.
3636 const kQueueSize = 2048 ;
3737 const kQueueMask = kQueueSize - 1 ;
3838
39+ // The next tick queue is implemented as a singly-linked list of fixed-size
40+ // circular buffers. It looks something like this:
41+ //
42+ // head tail
43+ // | |
44+ // v v
45+ // +-----------+ <-----\ +-----------+ <------\ +-----------+
46+ // | [null] | \----- | next | \------- | next |
47+ // +-----------+ +-----------+ +-----------+
48+ // | tick | <-- bottom | tick | <-- bottom | [empty] |
49+ // | tick | | tick | | [empty] |
50+ // | tick | | tick | | [empty] |
51+ // | tick | | tick | | [empty] |
52+ // | tick | | tick | bottom --> | tick |
53+ // | tick | | tick | | tick |
54+ // | ... | | ... | | ... |
55+ // | tick | | tick | | tick |
56+ // | tick | | tick | | tick |
57+ // | [empty] | <-- top | tick | | tick |
58+ // | [empty] | | tick | | tick |
59+ // | [empty] | | tick | | tick |
60+ // +-----------+ +-----------+ <-- top top --> +-----------+
61+ //
62+ // Or, if there is only one fixed-size queue, it looks something
63+ // like either of these:
64+ //
65+ // head tail head tail
66+ // | | | |
67+ // v v v v
68+ // +-----------+ +-----------+
69+ // | [null] | | [null] |
70+ // +-----------+ +-----------+
71+ // | [empty] | | tick |
72+ // | [empty] | | tick |
73+ // | tick | <-- bottom top --> | [empty] |
74+ // | tick | | [empty] |
75+ // | [empty] | <-- top bottom --> | tick |
76+ // | [empty] | | tick |
77+ // +-----------+ +-----------+
78+ //
79+ // Adding a value means moving `top` forward by one, removing means
80+ // moving `bottom` forward by one.
81+ //
82+ // We let `bottom` and `top` wrap around, so when `top` is conceptually
83+ // pointing to the end of the list, that means that the actual value is `0`.
84+ //
85+ // In particular, when `top === bottom`, this can mean *either* that the
86+ // current queue is empty or that it is full. We can differentiate by
87+ // checking whether an entry in the queue is empty (a.k.a. `=== undefined`).
88+
3989 class FixedQueue {
4090 constructor ( ) {
4191 this . bottom = 0 ;
@@ -50,11 +100,12 @@ function setupNextTick() {
50100 }
51101
52102 shift ( ) {
53- const next = this . list [ this . bottom ] ;
54- if ( next === undefined ) return null ;
103+ const nextItem = this . list [ this . bottom ] ;
104+ if ( nextItem === undefined )
105+ return null ;
55106 this . list [ this . bottom ] = undefined ;
56107 this . bottom = ( this . bottom + 1 ) & kQueueMask ;
57- return next ;
108+ return nextItem ;
58109 }
59110 }
60111
@@ -63,21 +114,34 @@ function setupNextTick() {
63114
64115 function push ( data ) {
65116 if ( head . bottom === head . top ) {
66- if ( head . list [ head . top ] !== undefined )
117+ // Either empty or full:
118+ if ( head . list [ head . top ] !== undefined ) {
119+ // It's full: Creates a new queue, sets the old queue's `.next` to it,
120+ // and sets it as the new main queue.
67121 head = head . next = new FixedQueue ( ) ;
68- else
122+ } else {
123+ // If the head is empty, that means that it was the only fixed-sized
124+ // queue in existence.
125+ DCHECK_EQ ( head . next , null ) ;
126+ // This is the first tick object in existence, so we need to inform
127+ // the C++ side that we do want to run `_tickCallback()`.
69128 tickInfo [ kHasScheduled ] = 1 ;
129+ }
70130 }
71131 head . push ( data ) ;
72132 }
73133
74134 function shift ( ) {
75135 const next = tail . shift ( ) ;
76- if ( tail . top === tail . bottom ) {
77- if ( tail . next )
136+ if ( tail . top === tail . bottom ) { // -> .shift() emptied the current queue.
137+ if ( tail . next !== null ) {
138+ // If there is another queue, it forms the new tail.
78139 tail = tail . next ;
79- else
140+ } else {
141+ // We've just run out of items. Let the native side know that it
142+ // doesn't need to bother calling into JS to run the queue.
80143 tickInfo [ kHasScheduled ] = 0 ;
144+ }
81145 }
82146 return next ;
83147 }
0 commit comments