Skip to content

Instantly share code, notes, and snippets.

@pdokas
Last active December 28, 2015 11:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pdokas/7493326 to your computer and use it in GitHub Desktop.
Save pdokas/7493326 to your computer and use it in GitHub Desktop.
var asap = (function(global) {
"use strict";
// 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 hasSetImmediate = typeof setImmediate === "function";
var domain;
// Avoid shims from browserify.
// The existence of `global` in browsers is guaranteed by browserify.
var process = global.process;
// Note that some fake-Node environments,
// like the Mocha test runner, introduce a `process` global.
var isNodeJS = !!process && ({}).toString.call(process) === "[object process]";
function flush() {
/* jshint loopfunc: true */
while (head.next) {
head = head.next;
var task = head.task;
head.task = void 0;
try {
task();
} catch (e) {
if (isNodeJS) {
// In node, uncaught exceptions are considered fatal errors.
// Re-throw them to interrupt flushing!
// Ensure continuation if an uncaught exception is suppressed
// listening process.on("uncaughtException") or domain("error").
requestFlush();
throw e;
} else {
// In browsers, uncaught exceptions are not fatal.
// Re-throw them asynchronously to avoid slow-downs.
setTimeout(function () {
throw e;
}, 0);
}
}
}
flushing = false;
}
if (isNodeJS) {
// Node.js
requestFlush = function () {
// Ensure flushing is not bound to any domain.
var currentDomain = process.domain;
if (currentDomain) {
domain = domain || (1,require)("domain");
domain.active = process.domain = null;
}
// Avoid tick recursion - use setImmediate if it exists.
if (flushing && hasSetImmediate) {
setImmediate(flush);
} else {
process.nextTick(flush);
}
if (currentDomain) {
domain.active = process.domain = currentDomain;
}
};
} else if (hasSetImmediate) {
// In IE10, or https://github.com/NobleJS/setImmediate
requestFlush = function () {
setImmediate(flush);
};
} else if (typeof MessageChannel !== "undefined") {
// modern browsers
// http://www.nonblocking.io/2011/06/windownexttick.html
var channel = new MessageChannel();
// At least Safari Version 6.0.5 (8536.30.1) intermittently cannot create
// working message ports the first time a page loads.
channel.port1.onmessage = function () {
requestFlush = requestPortFlush;
channel.port1.onmessage = flush;
flush();
};
var requestPortFlush = function () {
// Opera requires us to provide a message payload, regardless of
// whether we use it.
channel.port2.postMessage(0);
};
requestFlush = function () {
setTimeout(flush, 0);
requestPortFlush();
};
} else {
// old browsers
requestFlush = function () {
setTimeout(flush, 0);
};
}
function asap(task) {
if (isNodeJS && process.domain) {
task = process.domain.bind(task);
}
tail = tail.next = {task: task, next: null};
if (!flushing) {
requestFlush();
flushing = true;
}
};
return asap;
})(this);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment