Used: q-spec.js@a1a416.
Implementations compared:
This is currently in Q:
// http://www.nonblocking.io/2011/06/windownexttick.html
var channel = new MessageChannel();
// linked list of tasks (single, with head node)
var head = {}, tail = head;
channel.port1.onmessage = function () {
head = head.next;
var task = head.task;
delete head.task;
task();
};
nextTick = function (task) {
tail = tail.next = {task: task};
channel.port2.postMessage(0);
};
Notably Firefox does not have a MessageChannel
interface, so it falls back to setTimeout(task, 0)
.
There were reports of this being faster, so I tried the following implementation:
var MESSAGE = "q-nextTick-" + Math.random();
// linked list of tasks (single, with head node)
var head = {}, tail = head;
var onGlobalMessage = function (event) {
// This will catch all incoming messages (even from other
// windows), so make sure we're getting a message we triggered.
if (event.source === window && event.data === MESSAGE) {
head = head.next;
var task = head.task;
delete head.task;
task();
}
};
if (window.addEventListener) {
window.addEventListener("message", onGlobalMessage, false);
} else {
window.attachEvent("onmessage", onGlobalMessage);
}
nextTick = function (task) {
tail = tail.next = {task: task};
postMessage(MESSAGE, "*");
};
In IE10, there is a msSetImmediate
function available, based on the Efficient Script Yielding draft. Notably, it must be called as a method of window
, so we need to do
nextTick = msSetImmediate.bind(window);
In Firefox, MessageChannel
is not available, so currently in Q it falls back to
nextTick = function (task) {
setTimeout(task, 0);
};
I ran the Q test suite three times in a variety of settings. Here are the results, in seconds. Not amazingly scientific, but still data.
Firefox postMessage: 4.61, 3.72, 4.63
Firefox setTimeout: 3.34, 3.51, 3.46
Chrome postMessage: 1.25, 1.30, 1.31
Chrome MessageChannel: 1.30, 1.30, 1.29
IE10 in IE9 mode, postMessage: 1.08, 1.07, 1.08
IE10 in IE9 mode, MessageChannel: 1.64, 1.70, 1.65
IE10 in IE10 mode, msSetImmediate: 0.99, 1.02, 1.03
The results indicate a few interesting things. Note that all these conclusions really only apply to the Q test suite, which may not necessarily be a good general test suite for efficient script yielding.
postMessage
andMessageChannel
are not appreciably different in Chrome. In IE9postMessage
has a slight advantage.- Using
postMessage
in Firefox is actually slower than usingsetTimeout
(!) msSetImmediate
is just barely faster thanpostMessage
.
Thus, to conclude, it seems Q should stay with its current strategy, which is to only try MessageChannel
before moving back to setTimeout
.