@@ -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