public
Last active

Q test suite nextTick results

  • Download Gist
q-nexttick-times.md
Markdown

Comparing Different Implementations of process.nextTick using the Q test suite.

Used: q-spec.js@a1a416.

Implementations compared:

Based on MessageChannel

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).

Based on postMessage

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, "*");
};

Based on msSetImmediate

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);

Based on setTimeout

In Firefox, MessageChannel is not available, so currently in Q it falls back to

nextTick = function (task) {
    setTimeout(task, 0);
};

Results

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 and MessageChannel are not appreciably different in Chrome. In IE9 postMessage has a slight advantage.
  • Using postMessage in Firefox is actually slower than using setTimeout (!)
  • msSetImmediate is just barely faster than postMessage.

Thus, to conclude, it seems Q should stay with its current strategy, which is to only try MessageChannel before moving back to setTimeout.

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.