Skip to content

Instantly share code, notes, and snippets.

@domenic
Created May 27, 2012 06:30
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save domenic/2802407 to your computer and use it in GitHub Desktop.
Save domenic/2802407 to your computer and use it in GitHub Desktop.
Q test suite nextTick results

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment