A shim for the setImmediate efficient script yielding API
A YuzuJS production
setImmediate.js is a highly cross-browser implementation of the
clearImmediate APIs, proposed 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.
setImmediate.js runs at “full speed” in the following browsers and environments, using various clever tricks:
MessageChannel, which I can't find solid info on.
In all other browsers we fall back to using
setTimeout, so it's always safe to use.
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; if you are looking solely for the control-flow ordering effects, use a microtask solution such as asap.
In Node.js versions below 0.9,
setImmediate is not available, but
process.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.
In Firefox 3+, Internet Explorer 9+, all modern WebKit browsers, and Opera 9.5+,
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.
postMessage has completely different semantics inside web workers, and so cannot be used there. So we turn to
MessageChannel, which has worse browser support, but does work inside a web worker.
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?
In the browser, include it with a
<script> tag; pretty simple.
In Node.js, do
npm install setimmediate
somewhere early in your app; it attaches to the global.