| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent d3d1ee7 commit a45f3f8
1 file changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -32,10 +32,60 @@ function setupNextTick() { | |||
| 32 | 32 | const kHasScheduled = 0; | |
| 33 | 33 | const kHasPromiseRejections = 1; | |
| 34 | 34 | ||
| 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. | ||
| 36 | 36 | const kQueueSize = 2048; | |
| 37 | 37 | const kQueueMask = kQueueSize - 1; | |
| 38 | 38 | ||
| 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 | + | ||
| 39 | 89 | class FixedQueue { | |
| 40 | 90 | constructor() { | |
| 41 | 91 | this.bottom = 0; | |
@@ -50,11 +100,12 @@ function setupNextTick() { | |||
| 50 | 100 | } | |
| 51 | 101 | ||
| 52 | 102 | 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; | ||
| 55 | 106 | this.list[this.bottom] = undefined; | |
| 56 | 107 | this.bottom = (this.bottom + 1) & kQueueMask; | |
| 57 | - return next; | ||
| 108 | + return nextItem; | ||
| 58 | 109 | } | |
| 59 | 110 | } | |
| 60 | 111 | ||
@@ -63,21 +114,34 @@ function setupNextTick() { | |||
| 63 | 114 | ||
| 64 | 115 | function push(data) { | |
| 65 | 116 | 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. | ||
| 67 | 121 | 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()`. | ||
| 69 | 128 | tickInfo[kHasScheduled] = 1; | |
| 129 | + } | ||
| 70 | 130 | } | |
| 71 | 131 | head.push(data); | |
| 72 | 132 | } | |
| 73 | 133 | ||
| 74 | 134 | function shift() { | |
| 75 | 135 | 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. | ||
| 78 | 139 | 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. | ||
| 80 | 143 | tickInfo[kHasScheduled] = 0; | |
| 144 | + } | ||
| 81 | 145 | } | |
| 82 | 146 | return next; | |
| 83 | 147 | } | |
| Back | FazBrowse Home | New Git URL |
0 commit comments