jsPerf.app is an online JavaScript performance benchmark test runner & jsperf.com mirror. It is a complete rewrite in homage to the once excellent jsperf.com now with hopefully a more modern & maintainable codebase.
jsperf.com URLs are mirrored at the same path, e.g:
https://jsperf.com/negative-modulo/2
Can be accessed at:
https://jsperf.app/negative-modulo/2
set immediate test
<script>
(function (global, undefined) {
"use strict";
if (global.setImmediate) {
return;
}
var nextHandle = 1; // Spec says greater than zero
var tasksByHandle = {};
var currentlyRunningATask = false;
var doc = global.document;
var setImmediate;
function addFromSetImmediateArguments(args) {
tasksByHandle[nextHandle] = partiallyApplied.apply(undefined, args);
return nextHandle++;
}
// 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 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;
}
}
}
}
function clearImmediate(handle) {
delete tasksByHandle[handle];
}
function installNextTickImplementation() {
setImmediate = function() {
var handle = addFromSetImmediateArguments(arguments);
process.nextTick(partiallyApplied(runIfPresent, 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() {
// Installs an event handler on `global` for the `message` event: see
// * https://developer.mozilla.org/en/DOM/window.postMessage
// * http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages
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));
}
};
if (global.addEventListener) {
global.addEventListener("message", onGlobalMessage, false);
} else {
global.attachEvent("onmessage", onGlobalMessage);
}
setImmediate = function() {
var handle = addFromSetImmediateArguments(arguments);
global.postMessage(messagePrefix + handle, "*");
return 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;
};
}
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 script = doc.createElement("script");
script.onreadystatechange = function () {
runIfPresent(handle);
script.onreadystatechange = null;
html.removeChild(script);
script = null;
};
html.appendChild(script);
return handle;
};
}
function installSetTimeoutImplementation() {
setImmediate = function() {
var handle = addFromSetImmediateArguments(arguments);
setTimeout(partiallyApplied(runIfPresent, handle), 0);
return handle;
};
}
// 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;
// Don't get fooled by e.g. browserify environments.
if ({}.toString.call(global.process) === "[object process]") {
// For Node.js before 0.9
installNextTickImplementation();
} 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();
}
attachTo.setImmediate = setImmediate;
attachTo.clearImmediate = clearImmediate;
}(new Function("return this")()));
setTimeout(function () {
if (!window.setImmediate) {
ui.benchmarks[0].options.defer = false;
}
if (!window.msSetImmediate) {
ui.benchmarks[2].options.defer = false;
}
if (!window.MessageChannel) {
ui.benchmarks[3].options.defer = false;
} else {
window.immediateChannel = new MessageChannel();
}
if ("onreadystatechange" in document.createElement("script")) {
window.readyStateChange = true;
} else {
ui.benchmarks[4].options.defer = false;
}
if (!window.postMessage) {
ui.benchmarks[5].options.defer = false;
} else {
window.immediateCallbacks = {};
var onGlobalMessage = function (event) {
if (event.source === window && event.data.indexOf('immediate') === 0) {
var handle = 'h' + event.data.substring(9);
immediateCallbacks[handle]();
delete immediateCallbacks[handle];
}
};
if (window.addEventListener) {
window.addEventListener("message", onGlobalMessage, false);
} else {
window.attachEvent("onmessage", onGlobalMessage);
}
}
window.setImmediateM = (function() {
var hiddenDiv = document.createElement("div");
var callbacks = [];
(new MutationObserver(function(records) {
var cbList = callbacks.slice();
callbacks.length = 0;
cbList.forEach(function(callback) { callback(); });
})).observe(hiddenDiv, { attributes: true });
return function setImmediate(callback) {
if( !callbacks.length) {
hiddenDiv.setAttribute('yes', 'no');
}
callbacks.push(callback);
};
})();
window.setImmediateO = (function() {
if (!Object.observe) return function(fn) { setTimeout(fn, 0); };
var dummy = { foo: 0 };
var callbacks = [];
Object.observe(dummy, function(records) {
var cbList = callbacks.slice();
callbacks.length = 0;
cbList.forEach(function(callback) { callback(); });
});
return function setImmediate(callback) {
if( !callbacks.length) {
dummy.foo++;
}
callbacks.push(callback);
};
})();
window.setImmediateP = (function() {
var callbacks = [];
function run() {
var cbList = callbacks.slice();
callbacks.length = 0;
cbList.forEach(function(callback) { callback(); });
};
return function setImmediate(callback) {
if(!callbacks.length)
new Promise(function(resolve,reject){resolve();}).then(run);
callbacks.push(callback);
};
})();
}, 0);
</script>Ready to run.
| Test | Ops/sec | |
|---|---|---|
| setImmediate | | ready |
| setTimeout | | ready |
| msSetImmediate | | ready |
| MessageChannel | | ready |
| readyStateChange | | ready |
| postMessage | | ready |
| requestAnimationFrame | | ready |
| image + data-url | | ready |
| MutationObserver | | ready |
| Object.observe | | ready |
| native Promises | | ready |
| setImmediate | | ready |
You can edit these tests or add more tests to this page by appending /edit to the URL.