You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
114 lines
2.8 KiB
JavaScript
114 lines
2.8 KiB
JavaScript
5 years ago
|
|
||
|
// Use the fastest possible means to execute a task in a future turn
|
||
|
// of the event loop.
|
||
|
|
||
|
// linked list of tasks (single, with head node)
|
||
|
var head = {task: void 0, next: null};
|
||
|
var tail = head;
|
||
|
var flushing = false;
|
||
|
var requestFlush = void 0;
|
||
|
var isNodeJS = false;
|
||
|
|
||
|
function flush() {
|
||
|
/* jshint loopfunc: true */
|
||
|
|
||
|
while (head.next) {
|
||
|
head = head.next;
|
||
|
var task = head.task;
|
||
|
head.task = void 0;
|
||
|
var domain = head.domain;
|
||
|
|
||
|
if (domain) {
|
||
|
head.domain = void 0;
|
||
|
domain.enter();
|
||
|
}
|
||
|
|
||
|
try {
|
||
|
task();
|
||
|
|
||
|
} catch (e) {
|
||
|
if (isNodeJS) {
|
||
|
// In node, uncaught exceptions are considered fatal errors.
|
||
|
// Re-throw them synchronously to interrupt flushing!
|
||
|
|
||
|
// Ensure continuation if the uncaught exception is suppressed
|
||
|
// listening "uncaughtException" events (as domains does).
|
||
|
// Continue in next event to avoid tick recursion.
|
||
|
if (domain) {
|
||
|
domain.exit();
|
||
|
}
|
||
|
setTimeout(flush, 0);
|
||
|
if (domain) {
|
||
|
domain.enter();
|
||
|
}
|
||
|
|
||
|
throw e;
|
||
|
|
||
|
} else {
|
||
|
// In browsers, uncaught exceptions are not fatal.
|
||
|
// Re-throw them asynchronously to avoid slow-downs.
|
||
|
setTimeout(function() {
|
||
|
throw e;
|
||
|
}, 0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (domain) {
|
||
|
domain.exit();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
flushing = false;
|
||
|
}
|
||
|
|
||
|
if (typeof process !== "undefined" && process.nextTick) {
|
||
|
// Node.js before 0.9. Note that some fake-Node environments, like the
|
||
|
// Mocha test runner, introduce a `process` global without a `nextTick`.
|
||
|
isNodeJS = true;
|
||
|
|
||
|
requestFlush = function () {
|
||
|
process.nextTick(flush);
|
||
|
};
|
||
|
|
||
|
} else if (typeof setImmediate === "function") {
|
||
|
// In IE10, Node.js 0.9+, or https://github.com/NobleJS/setImmediate
|
||
|
if (typeof window !== "undefined") {
|
||
|
requestFlush = setImmediate.bind(window, flush);
|
||
|
} else {
|
||
|
requestFlush = function () {
|
||
|
setImmediate(flush);
|
||
|
};
|
||
|
}
|
||
|
|
||
|
} else if (typeof MessageChannel !== "undefined") {
|
||
|
// modern browsers
|
||
|
// http://www.nonblocking.io/2011/06/windownexttick.html
|
||
|
var channel = new MessageChannel();
|
||
|
channel.port1.onmessage = flush;
|
||
|
requestFlush = function () {
|
||
|
channel.port2.postMessage(0);
|
||
|
};
|
||
|
|
||
|
} else {
|
||
|
// old browsers
|
||
|
requestFlush = function () {
|
||
|
setTimeout(flush, 0);
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function asap(task) {
|
||
|
tail = tail.next = {
|
||
|
task: task,
|
||
|
domain: isNodeJS && process.domain,
|
||
|
next: null
|
||
|
};
|
||
|
|
||
|
if (!flushing) {
|
||
|
flushing = true;
|
||
|
requestFlush();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
module.exports = asap;
|
||
|
|