Skip to content

Commit cfb78bc

Browse files
mafintoshaddaleax
authored andcommitted
process: use linked reusable queue for ticks
PR-URL: #18617 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]> Reviewed-By: Ruben Bridgewater <[email protected]> Reviewed-By: Anatoli Papirovski <[email protected]> Reviewed-By: Benedikt Meurer <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Luigi Pinca <[email protected]> Reviewed-By: Tiancheng "Timothy" Gu <[email protected]>
1 parent 4012ae8 commit cfb78bc

File tree

1 file changed

+49
-27
lines changed

1 file changed

+49
-27
lines changed

lib/internal/process/next_tick.js

+49-27
Original file line numberDiff line numberDiff line change
@@ -32,32 +32,55 @@ function setupNextTick() {
3232
const kHasScheduled = 0;
3333
const kHasPromiseRejections = 1;
3434

35-
const nextTickQueue = {
36-
head: null,
37-
tail: null,
35+
// Queue size for each tick array. Must be a factor of two.
36+
const kQueueSize = 2048;
37+
const kQueueMask = kQueueSize - 1;
38+
39+
class FixedQueue {
40+
constructor() {
41+
this.bottom = 0;
42+
this.top = 0;
43+
this.list = new Array(kQueueSize);
44+
this.next = null;
45+
}
46+
3847
push(data) {
39-
const entry = { data, next: null };
40-
if (this.tail !== null) {
41-
this.tail.next = entry;
42-
} else {
43-
this.head = entry;
44-
tickInfo[kHasScheduled] = 1;
45-
}
46-
this.tail = entry;
47-
},
48+
this.list[this.top] = data;
49+
this.top = (this.top + 1) & kQueueMask;
50+
}
51+
4852
shift() {
49-
if (this.head === null)
50-
return;
51-
const ret = this.head.data;
52-
if (this.head === this.tail) {
53-
this.head = this.tail = null;
53+
const next = this.list[this.bottom];
54+
if (next === undefined) return null;
55+
this.list[this.bottom] = undefined;
56+
this.bottom = (this.bottom + 1) & kQueueMask;
57+
return next;
58+
}
59+
}
60+
61+
var head = new FixedQueue();
62+
var tail = head;
63+
64+
function push(data) {
65+
if (head.bottom === head.top) {
66+
if (head.list[head.top] !== undefined)
67+
head = head.next = new FixedQueue();
68+
else
69+
tickInfo[kHasScheduled] = 1;
70+
}
71+
head.push(data);
72+
}
73+
74+
function shift() {
75+
const next = tail.shift();
76+
if (tail.top === tail.bottom) {
77+
if (tail.next)
78+
tail = tail.next;
79+
else
5480
tickInfo[kHasScheduled] = 0;
55-
} else {
56-
this.head = this.head.next;
57-
}
58-
return ret;
5981
}
60-
};
82+
return next;
83+
}
6184

6285
process.nextTick = nextTick;
6386
// Needs to be accessible from beyond this scope.
@@ -69,7 +92,7 @@ function setupNextTick() {
6992
function _tickCallback() {
7093
let tock;
7194
do {
72-
while (tock = nextTickQueue.shift()) {
95+
while (tock = shift()) {
7396
const asyncId = tock[async_id_symbol];
7497
emitBefore(asyncId, tock[trigger_async_id_symbol]);
7598
// emitDestroy() places the async_id_symbol into an asynchronous queue
@@ -93,7 +116,7 @@ function setupNextTick() {
93116
emitAfter(asyncId);
94117
}
95118
runMicrotasks();
96-
} while (nextTickQueue.head !== null || emitPromiseRejectionWarnings());
119+
} while (head.top !== head.bottom || emitPromiseRejectionWarnings());
97120
tickInfo[kHasPromiseRejections] = 0;
98121
}
99122

@@ -139,8 +162,7 @@ function setupNextTick() {
139162
args[i - 1] = arguments[i];
140163
}
141164

142-
nextTickQueue.push(new TickObject(callback, args,
143-
getDefaultTriggerAsyncId()));
165+
push(new TickObject(callback, args, getDefaultTriggerAsyncId()));
144166
}
145167

146168
// `internalNextTick()` will not enqueue any callback when the process is
@@ -168,6 +190,6 @@ function setupNextTick() {
168190

169191
if (triggerAsyncId === null)
170192
triggerAsyncId = getDefaultTriggerAsyncId();
171-
nextTickQueue.push(new TickObject(callback, args, triggerAsyncId));
193+
push(new TickObject(callback, args, triggerAsyncId));
172194
}
173195
}

0 commit comments

Comments
 (0)