Socket
Socket
Sign inDemoInstall

setimmediate

Package Overview
Dependencies
0
Maintainers
1
Versions
6
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.0.1 to 1.0.2

40

package.json
{
"name": "setimmediate",
"description": "A shim for the setImmediate efficient script yielding API",
"version": "1.0.1",
"author": "NobleJS",
"version": "1.0.2",
"author": "YuzuJS",
"contributors": [
"Domenic Denicola <domenic@domenicdenicola.com> (http://domenicdenicola.com)",
"Donavon West",
"Domenic Denicola <domenic@domenicdenicola.com> (http://domenic.me)",
"Donavon West <github@donavon.com> (http://donavon.com)",
"Yaffle"
],
"license": "MIT",
"repository": {
"type": "git",
"url": "git://github.com/NobleJS/setImmediate.git"
},
"bugs": {
"url": "http://github.com/NobleJS/setImmediate/issues"
},
"repository": "git://github.com/YuzuJS/setImmediate.git",
"bugs": "https://github.com/YuzuJS/setImmediate/issues",
"main": "setImmediate.js",

@@ -23,23 +18,12 @@ "scripts": {

"test": "mocha test/tests.js",
"test-browser": "opener http://localhost:9000 && zuul --server 9000 test/tests.js --wwwroot test/",
"test-browser": "opener http://localhost:9008/__zuul && zuul test/tests.js --ui mocha-bdd --local 9008",
"test-browser-only": "opener http://localhost:9007/test/browserOnly/index.html && http-server . -p 9007"
},
"devDependencies": {
"jshint": ">= 0.9.1",
"mocha": ">= 1.7.4",
"zuul": ">= 0.0.1",
"http-server": ">= 0.5.3",
"opener": ">= 1.1.0"
},
"testling": {
"browsers": {
"ie": [6, 7, 8, 9],
"chrome": [4, 23, "canary"],
"firefox": [3, 3.5, 3.6, 4, 17, "nightly"],
"opera": [10, 10.5, 11, 11.5, 11.6, 12, "next"],
"safari": ["5.0.5", 5.1]
},
"harness": "mocha",
"files": "test/tests.js"
"jshint": "^2.5.0",
"mocha": "~1.18.2",
"http-server": "~0.6.1",
"opener": "^1.3",
"zuul": "^1.6.4"
}
}

@@ -1,15 +0,7 @@

<a href="http://ci.testling.com/NobleJS/setImmediate">
<img src="http://ci.testling.com/NobleJS/setImmediate.png" alt="Testling-CI badge showing browser compliance"
align="right">
</a>
# setImmediate.js
**A NobleJS production**
**A YuzuJS production**
## Introduction
**setImmediate.js** is a highly cross-browser implementation of the `setImmediate` and `clearImmediate` APIs, currently
a [W3C draft spec][spec] from the Web Performance Working Group. `setImmediate` allows scripts to yield to the browser,
executing a given operation asynchronously, in a manner that is typically more efficient and consumes less power than
the usual `setTimeout(..., 0)` pattern.
**setImmediate.js** is a highly cross-browser implementation of the `setImmediate` and `clearImmediate` APIs, [proposed][spec] by Microsoft to the Web Performance Working Group. `setImmediate` allows scripts to yield to the browser, executing a given operation asynchronously, in a manner that is typically more efficient and consumes less power than the usual `setTimeout(..., 0)` pattern.

@@ -27,2 +19,10 @@ setImmediate.js runs at “full speed” in the following browsers and environments, using various clever tricks:

## Macrotasks and Microtasks
The `setImmediate` API, as specified, gives you access to the environment's [task queue][], sometimes known as its "macrotask" queue. This is crucially different from the [microtask queue][] used by web features such as `MutationObserver`, language features such as promises and `Object.observe`, and Node.js features such as `process.nextTick`. Each go-around of the macrotask queue yields back to the event loop once all queued tasks have been processed, even if the macrotask itself queued more macrotasks. Whereas, the microtask queue will continue executing any queued microtasks until it is exhausted.
In practice, what this means is that if you call `setImmediate` inside of another task queued with `setImmediate`, you will yield back to the event loop and any I/O or rendering tasks that need to take place between those calls, instead of executing the queued task as soon as possible.
If you are looking specifically to yield as part of a render loop, consider using [`requestAnimationFrame`][raf]; if you are looking solely for the control-flow ordering effects, use a microtask solution such as [asap][].
## The Tricks

@@ -32,29 +32,19 @@

In Node.js versions below 0.9, `setImmediate` is not available, but [`process.nextTick`][nextTIck] is, so we use it to
shim support for a global `setImmediate`. In Node.js 0.9 and above, `setImmediate` is available.
In Node.js versions below 0.9, `setImmediate` is not available, but [`process.nextTick`][nextTIck] is, so we use it to shim support for a global `setImmediate`. In Node.js 0.9 and above, `setImmediate` is available.
Note that we check for *actual* Node.js environments, not emulated ones like those produced by browserify or similar.
Such emulated environments often already include a `process.nextTick` shim that's not as browser-compatible as
setImmediate.js.
Note that we check for *actual* Node.js environments, not emulated ones like those produced by browserify or similar. Such emulated environments often already include a `process.nextTick` shim that's not as browser-compatible as setImmediate.js.
### `postMessage`
In Firefox 3+, Internet Explorer 9+, all modern WebKit browsers, and Opera 9.5+, [`postMessage`][postMessage] is
available and provides a good way to queue tasks on the event loop. It's quite the abuse, using a cross-document
messaging protocol within the same document simply to get access to the event loop task queue, but until there are
native implementations, this is the best option.
In Firefox 3+, Internet Explorer 9+, all modern WebKit browsers, and Opera 9.5+, [`postMessage`][postMessage] is available and provides a good way to queue tasks on the event loop. It's quite the abuse, using a cross-document messaging protocol within the same document simply to get access to the event loop task queue, but until there are native implementations, this is the best option.
Note that Internet Explorer 8 includes a synchronous version of `postMessage`. We detect this, or any other such
synchronous implementation, and fall back to another trick.
Note that Internet Explorer 8 includes a synchronous version of `postMessage`. We detect this, or any other such synchronous implementation, and fall back to another trick.
### `MessageChannel`
Unfortunately, `postMessage` has completely different semantics inside web workers, and so cannot be used there. So we
turn to [`MessageChannel`][MessageChannel], which has worse browser support, but does work inside a web worker.
Unfortunately, `postMessage` has completely different semantics inside web workers, and so cannot be used there. So we turn to [`MessageChannel`][MessageChannel], which has worse browser support, but does work inside a web worker.
### `<script> onreadystatechange`
For our last trick, we pull something out to make things fast in Internet Explorer versions 6 through 8: namely,
creating a `<script>` element and firing our calls in its `onreadystatechange` event. This does execute in a future
turn of the event loop, and is also faster than `setTimeout(…, 0)`, so hey, why not?
For our last trick, we pull something out to make things fast in Internet Explorer versions 6 through 8: namely, creating a `<script>` element and firing our calls in its `onreadystatechange` event. This does execute in a future turn of the event loop, and is also faster than `setTimeout(…, 0)`, so hey, why not?

@@ -82,3 +72,3 @@ ## Usage

* [Quick sort demo][cross-browser-demo]
## Reference and Reading

@@ -93,2 +83,6 @@

[spec]: https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/setImmediate/Overview.html
[task queue]: http://www.whatwg.org/specs/web-apps/current-work/multipage/webappapis.html#task-queue
[microtask queue]: http://www.whatwg.org/specs/web-apps/current-work/multipage/webappapis.html#perform-a-microtask-checkpoint
[raf]: www.w3.org/TR/animation-timing/
[asap]: https://github.com/kriskowal/asap
[list-post]: http://lists.w3.org/Archives/Public/public-web-perf/2011Jun/0100.html

@@ -95,0 +89,0 @@ [ie-demo]: http://ie.microsoft.com/testdrive/Performance/setImmediateSorting/Default.html

(function (global, undefined) {
"use strict";
var tasks = (function () {
function Task(handler, args) {
this.handler = handler;
this.args = args;
}
Task.prototype.run = function () {
// See steps in section 5 of the spec.
if (typeof this.handler === "function") {
// Choice of `thisArg` is not in the setImmediate spec; `undefined` is in the setTimeout spec though:
// http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html
this.handler.apply(undefined, this.args);
} else {
var scriptSource = "" + this.handler;
/*jshint evil: true */
eval(scriptSource);
}
};
if (global.setImmediate) {
return;
}
var nextHandle = 1; // Spec says greater than zero
var tasksByHandle = {};
var currentlyRunningATask = false;
var nextHandle = 1; // Spec says greater than zero
var tasksByHandle = {};
var currentlyRunningATask = false;
var doc = global.document;
var setImmediate;
return {
addFromSetImmediateArguments: function (args) {
var handler = args[0];
var argsToHandle = Array.prototype.slice.call(args, 1);
var task = new Task(handler, argsToHandle);
function addFromSetImmediateArguments(args) {
tasksByHandle[nextHandle] = partiallyApplied.apply(undefined, args);
return nextHandle++;
}
var thisHandle = nextHandle++;
tasksByHandle[thisHandle] = task;
return thisHandle;
},
runIfPresent: function (handle) {
// From the spec: "Wait until any invocations of this algorithm started before this one have completed."
// So if we're currently running a task, we'll need to delay this invocation.
if (!currentlyRunningATask) {
var task = tasksByHandle[handle];
if (task) {
currentlyRunningATask = true;
try {
task.run();
} finally {
delete tasksByHandle[handle];
currentlyRunningATask = false;
}
}
} else {
// Delay by doing a setTimeout. setImmediate was tried instead, but in Firefox 7 it generated a
// "too much recursion" error.
global.setTimeout(function () {
tasks.runIfPresent(handle);
}, 0);
}
},
remove: function (handle) {
delete tasksByHandle[handle];
// This function accepts the same arguments as setImmediate, but
// returns a function that requires no arguments.
function partiallyApplied(handler) {
var args = [].slice.call(arguments, 1);
return function() {
if (typeof handler === "function") {
handler.apply(undefined, args);
} else {
(new Function("" + handler))();
}
};
}());
function canUseNextTick() {
// Don't get fooled by e.g. browserify environments.
return typeof process === "object" &&
Object.prototype.toString.call(process) === "[object process]";
}
function canUseMessageChannel() {
return !!global.MessageChannel;
}
function canUsePostMessage() {
// The test against `importScripts` prevents this implementation from being installed inside a web worker,
// where `global.postMessage` means something completely different and can't be used for this purpose.
if (!global.postMessage || global.importScripts) {
return false;
function runIfPresent(handle) {
// From the spec: "Wait until any invocations of this algorithm started before this one have completed."
// So if we're currently running a task, we'll need to delay this invocation.
if (currentlyRunningATask) {
// Delay by doing a setTimeout. setImmediate was tried instead, but in Firefox 7 it generated a
// "too much recursion" error.
setTimeout(partiallyApplied(runIfPresent, handle), 0);
} else {
var task = tasksByHandle[handle];
if (task) {
currentlyRunningATask = true;
try {
task();
} finally {
clearImmediate(handle);
currentlyRunningATask = false;
}
}
}
var postMessageIsAsynchronous = true;
var oldOnMessage = global.onmessage;
global.onmessage = function () {
postMessageIsAsynchronous = false;
};
global.postMessage("", "*");
global.onmessage = oldOnMessage;
return postMessageIsAsynchronous;
}
function canUseReadyStateChange() {
return "document" in global && "onreadystatechange" in global.document.createElement("script");
function clearImmediate(handle) {
delete tasksByHandle[handle];
}
function installNextTickImplementation(attachTo) {
attachTo.setImmediate = function () {
var handle = tasks.addFromSetImmediateArguments(arguments);
process.nextTick(function () {
tasks.runIfPresent(handle);
});
function installNextTickImplementation() {
setImmediate = function() {
var handle = addFromSetImmediateArguments(arguments);
process.nextTick(partiallyApplied(runIfPresent, handle));
return handle;

@@ -109,18 +65,18 @@ };

function installMessageChannelImplementation(attachTo) {
var channel = new global.MessageChannel();
channel.port1.onmessage = function (event) {
var handle = event.data;
tasks.runIfPresent(handle);
};
attachTo.setImmediate = function () {
var handle = tasks.addFromSetImmediateArguments(arguments);
channel.port2.postMessage(handle);
return handle;
};
function canUsePostMessage() {
// The test against `importScripts` prevents this implementation from being installed inside a web worker,
// where `global.postMessage` means something completely different and can't be used for this purpose.
if (global.postMessage && !global.importScripts) {
var postMessageIsAsynchronous = true;
var oldOnMessage = global.onmessage;
global.onmessage = function() {
postMessageIsAsynchronous = false;
};
global.postMessage("", "*");
global.onmessage = oldOnMessage;
return postMessageIsAsynchronous;
}
}
function installPostMessageImplementation(attachTo) {
function installPostMessageImplementation() {
// Installs an event handler on `global` for the `message` event: see

@@ -130,17 +86,11 @@ // * https://developer.mozilla.org/en/DOM/window.postMessage

var MESSAGE_PREFIX = "com.bn.NobleJS.setImmediate" + Math.random();
var messagePrefix = "setImmediate$" + Math.random() + "$";
var onGlobalMessage = function(event) {
if (event.source === global &&
typeof event.data === "string" &&
event.data.indexOf(messagePrefix) === 0) {
runIfPresent(+event.data.slice(messagePrefix.length));
}
};
function isStringAndStartsWith(string, putativeStart) {
return typeof string === "string" && string.substring(0, putativeStart.length) === putativeStart;
}
function onGlobalMessage(event) {
// This will catch all incoming messages (even from other windows!), so we need to try reasonably hard to
// avoid letting anyone else trick us into firing off. We test the origin is still this window, and that a
// (randomly generated) unpredictable identifying prefix is present.
if (event.source === global && isStringAndStartsWith(event.data, MESSAGE_PREFIX)) {
var handle = event.data.substring(MESSAGE_PREFIX.length);
tasks.runIfPresent(handle);
}
}
if (global.addEventListener) {

@@ -152,9 +102,19 @@ global.addEventListener("message", onGlobalMessage, false);

attachTo.setImmediate = function () {
var handle = tasks.addFromSetImmediateArguments(arguments);
setImmediate = function() {
var handle = addFromSetImmediateArguments(arguments);
global.postMessage(messagePrefix + handle, "*");
return handle;
};
}
// Make `global` post a message to itself with the handle and identifying prefix, thus asynchronously
// invoking our onGlobalMessage listener above.
global.postMessage(MESSAGE_PREFIX + handle, "*");
function installMessageChannelImplementation() {
var channel = new MessageChannel();
channel.port1.onmessage = function(event) {
var handle = event.data;
runIfPresent(handle);
};
setImmediate = function() {
var handle = addFromSetImmediateArguments(arguments);
channel.port2.postMessage(handle);
return handle;

@@ -164,18 +124,16 @@ };

function installReadyStateChangeImplementation(attachTo) {
attachTo.setImmediate = function () {
var handle = tasks.addFromSetImmediateArguments(arguments);
function installReadyStateChangeImplementation() {
var html = doc.documentElement;
setImmediate = function() {
var handle = addFromSetImmediateArguments(arguments);
// Create a <script> element; its readystatechange event will be fired asynchronously once it is inserted
// into the document. Do so, thus queuing up the task. Remember to clean up once it's been called.
var scriptEl = global.document.createElement("script");
scriptEl.onreadystatechange = function () {
tasks.runIfPresent(handle);
scriptEl.onreadystatechange = null;
scriptEl.parentNode.removeChild(scriptEl);
scriptEl = null;
var script = doc.createElement("script");
script.onreadystatechange = function () {
runIfPresent(handle);
script.onreadystatechange = null;
html.removeChild(script);
script = null;
};
global.document.documentElement.appendChild(scriptEl);
html.appendChild(script);
return handle;

@@ -185,10 +143,6 @@ };

function installSetTimeoutImplementation(attachTo) {
attachTo.setImmediate = function () {
var handle = tasks.addFromSetImmediateArguments(arguments);
global.setTimeout(function () {
tasks.runIfPresent(handle);
}, 0);
function installSetTimeoutImplementation() {
setImmediate = function() {
var handle = addFromSetImmediateArguments(arguments);
setTimeout(partiallyApplied(runIfPresent, handle), 0);
return handle;

@@ -198,27 +152,30 @@ };

if (!global.setImmediate) {
// If supported, we should attach to the prototype of global, since that is where setTimeout et al. live.
var attachTo = typeof Object.getPrototypeOf === "function" && "setTimeout" in Object.getPrototypeOf(global) ?
Object.getPrototypeOf(global)
: global;
// If supported, we should attach to the prototype of global, since that is where setTimeout et al. live.
var attachTo = Object.getPrototypeOf && Object.getPrototypeOf(global);
attachTo = attachTo && attachTo.setTimeout ? attachTo : global;
if (canUseNextTick()) {
// For Node.js before 0.9
installNextTickImplementation(attachTo);
} else if (canUsePostMessage()) {
// For non-IE10 modern browsers
installPostMessageImplementation(attachTo);
} else if (canUseMessageChannel()) {
// For web workers, where supported
installMessageChannelImplementation(attachTo);
} else if (canUseReadyStateChange()) {
// For IE 6–8
installReadyStateChangeImplementation(attachTo);
} else {
// For older browsers
installSetTimeoutImplementation(attachTo);
}
// Don't get fooled by e.g. browserify environments.
if ({}.toString.call(global.process) === "[object process]") {
// For Node.js before 0.9
installNextTickImplementation();
attachTo.clearImmediate = tasks.remove;
} else if (canUsePostMessage()) {
// For non-IE10 modern browsers
installPostMessageImplementation();
} else if (global.MessageChannel) {
// For web workers, where supported
installMessageChannelImplementation();
} else if (doc && "onreadystatechange" in doc.createElement("script")) {
// For IE 6–8
installReadyStateChangeImplementation();
} else {
// For older browsers
installSetTimeoutImplementation();
}
}(typeof global === "object" && global ? global : this));
attachTo.setImmediate = setImmediate;
attachTo.clearImmediate = clearImmediate;
}(new Function("return this")()));
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc