mirror of https://github.com/lukechilds/node.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
157 lines
4.2 KiB
157 lines
4.2 KiB
'use strict';
|
|
|
|
exports.setup = setupNextTick;
|
|
|
|
function setupNextTick() {
|
|
const promises = require('internal/process/promises');
|
|
const emitPendingUnhandledRejections = promises.setup(scheduleMicrotasks);
|
|
var nextTickQueue = [];
|
|
var microtasksScheduled = false;
|
|
|
|
// Used to run V8's micro task queue.
|
|
var _runMicrotasks = {};
|
|
|
|
// *Must* match Environment::TickInfo::Fields in src/env.h.
|
|
var kIndex = 0;
|
|
var kLength = 1;
|
|
|
|
process.nextTick = nextTick;
|
|
// Needs to be accessible from beyond this scope.
|
|
process._tickCallback = _tickCallback;
|
|
process._tickDomainCallback = _tickDomainCallback;
|
|
|
|
// This tickInfo thing is used so that the C++ code in src/node.cc
|
|
// can have easy access to our nextTick state, and avoid unnecessary
|
|
// calls into JS land.
|
|
const tickInfo = process._setupNextTick(_tickCallback, _runMicrotasks);
|
|
|
|
_runMicrotasks = _runMicrotasks.runMicrotasks;
|
|
|
|
function tickDone() {
|
|
if (tickInfo[kLength] !== 0) {
|
|
if (tickInfo[kLength] <= tickInfo[kIndex]) {
|
|
nextTickQueue = [];
|
|
tickInfo[kLength] = 0;
|
|
} else {
|
|
nextTickQueue.splice(0, tickInfo[kIndex]);
|
|
tickInfo[kLength] = nextTickQueue.length;
|
|
}
|
|
}
|
|
tickInfo[kIndex] = 0;
|
|
}
|
|
|
|
function scheduleMicrotasks() {
|
|
if (microtasksScheduled)
|
|
return;
|
|
|
|
nextTickQueue.push({
|
|
callback: runMicrotasksCallback,
|
|
domain: null
|
|
});
|
|
|
|
tickInfo[kLength]++;
|
|
microtasksScheduled = true;
|
|
}
|
|
|
|
function runMicrotasksCallback() {
|
|
microtasksScheduled = false;
|
|
_runMicrotasks();
|
|
|
|
if (tickInfo[kIndex] < tickInfo[kLength] ||
|
|
emitPendingUnhandledRejections())
|
|
scheduleMicrotasks();
|
|
}
|
|
|
|
function _combinedTickCallback(args, callback) {
|
|
if (args === undefined) {
|
|
callback();
|
|
} else {
|
|
switch (args.length) {
|
|
case 1:
|
|
callback(args[0]);
|
|
break;
|
|
case 2:
|
|
callback(args[0], args[1]);
|
|
break;
|
|
case 3:
|
|
callback(args[0], args[1], args[2]);
|
|
break;
|
|
default:
|
|
callback.apply(null, args);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Run callbacks that have no domain.
|
|
// Using domains will cause this to be overridden.
|
|
function _tickCallback() {
|
|
var callback, args, tock;
|
|
|
|
do {
|
|
while (tickInfo[kIndex] < tickInfo[kLength]) {
|
|
tock = nextTickQueue[tickInfo[kIndex]++];
|
|
callback = tock.callback;
|
|
args = tock.args;
|
|
// Using separate callback execution functions allows direct
|
|
// callback invocation with small numbers of arguments to avoid the
|
|
// performance hit associated with using `fn.apply()`
|
|
_combinedTickCallback(args, callback);
|
|
if (1e4 < tickInfo[kIndex])
|
|
tickDone();
|
|
}
|
|
tickDone();
|
|
_runMicrotasks();
|
|
emitPendingUnhandledRejections();
|
|
} while (tickInfo[kLength] !== 0);
|
|
}
|
|
|
|
function _tickDomainCallback() {
|
|
var callback, domain, args, tock;
|
|
|
|
do {
|
|
while (tickInfo[kIndex] < tickInfo[kLength]) {
|
|
tock = nextTickQueue[tickInfo[kIndex]++];
|
|
callback = tock.callback;
|
|
domain = tock.domain;
|
|
args = tock.args;
|
|
if (domain)
|
|
domain.enter();
|
|
// Using separate callback execution functions allows direct
|
|
// callback invocation with small numbers of arguments to avoid the
|
|
// performance hit associated with using `fn.apply()`
|
|
_combinedTickCallback(args, callback);
|
|
if (1e4 < tickInfo[kIndex])
|
|
tickDone();
|
|
if (domain)
|
|
domain.exit();
|
|
}
|
|
tickDone();
|
|
_runMicrotasks();
|
|
emitPendingUnhandledRejections();
|
|
} while (tickInfo[kLength] !== 0);
|
|
}
|
|
|
|
function TickObject(c, args) {
|
|
this.callback = c;
|
|
this.domain = process.domain || null;
|
|
this.args = args;
|
|
}
|
|
|
|
function nextTick(callback) {
|
|
if (typeof callback !== 'function')
|
|
throw new TypeError('callback is not a function');
|
|
// on the way out, don't bother. it won't get fired anyway.
|
|
if (process._exiting)
|
|
return;
|
|
|
|
var args;
|
|
if (arguments.length > 1) {
|
|
args = new Array(arguments.length - 1);
|
|
for (var i = 1; i < arguments.length; i++)
|
|
args[i - 1] = arguments[i];
|
|
}
|
|
|
|
nextTickQueue.push(new TickObject(callback, args));
|
|
tickInfo[kLength]++;
|
|
}
|
|
}
|
|
|