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
<p id="message"></p>
<div id="haystack"></div>
<script id="style-template" type="text/css-template">
@-moz-keyframes nodeInserted {
from {
clip: rect(1px, auto, auto, auto);
}
to {
clip: rect(0px, auto, auto, auto);
}
}
@-webkit-keyframes nodeInserted {
from {
clip: rect(1px, auto, auto, auto);
}
to {
clip: rect(0px, auto, auto, auto);
}
}
@-ms-keyframes nodeInserted {
from {
clip: rect(1px, auto, auto, auto);
}
to {
clip: rect(0px, auto, auto, auto);
}
}
@-o-keyframes nodeInserted {
from {
clip: rect(1px, auto, auto, auto);
}
to {
clip: rect(0px, auto, auto, auto);
}
}
@keyframes nodeInserted {
from {
clip: rect(1px, auto, auto, auto);
}
to {
clip: rect(0px, auto, auto, auto);
}
}
.inserted {
-o-animation-duration: 0.001s;
-ms-animation-duration: 0.001s;
-moz-animation-duration: 0.001s;
-webkit-animation-duration: 0.001s;
animation-duration: 0.001s;
-o-animation-name: nodeInserted;
-ms-animation-name: nodeInserted;
-moz-animation-name: nodeInserted;
-webkit-animation-name: nodeInserted;
animation-name: nodeInserted;
}
</script>
<script>
console.log("preparation");
var haystack = document.getElementById("haystack");
var html = '';
var batch = 100;
for (var i = 0; i < batch; ++i) {
html += '<span class="inserted"></span>';
}
function setHaystack() {
j = 0;
haystack.innerHTML = html;
}
var isInserted = function(node) {
return node.className === 'inserted';
};
var globalDeferred;
var resolve = function() {
if (globalDeferred) {
var tmpDeferred = globalDeferred;
globalDeferred = null;
tmpDeferred.resolve();
} else {
throw 'globalDeferred not found';
}
};
var setMessage = function(messageHtml) {
document.getElementById("message").innerHTML = messageHtml;
};
var mutationListener = function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.type === "childList" && mutation.addedNodes && mutation.addedNodes.length === batch) {
resolve();
}
});
};
var observer;
if (window.MutationObserver) {
setMessage("Your browser supports <code>MutationObserver</code>.");
observer = new MutationObserver(mutationListener);
} else if (window.WebKitMutationObserver) {
setMessage("Your browser supports <code>WebKitMutationObserver</code>.");
observer = new WebKitMutationObserver(mutationListener);
} else {
setMessage("Your browser does not support <code>MutationObserver</code>. You will not be able to run these tests.");
}
var animationType;
var j = 0;
function foundOne(sync) {
++j;
if (j === batch) {
if(sync){
window.addEventListener('message', function onMessage(e){
if(e.data === '__m'){
window.removeEventListener('message', onMessage, false);
resolve();
}
}, false);
window.postMessage('__m','*');
}else{
resolve();
}
j = 0;
}
}
var animationListener = function(event) {
var type = event.type;
if (!animationType) {
animationType = type;
} else if (animationType !== type) {
return;
}
if (event.animationName === "nodeInserted") {
foundOne();
}
};
var nodeInsertedListener = function(event) {
if (isInserted(event.target)) {
foundOne(true);
}
};
// Note: cannot use global setup when using ui.benchmarks[i].setup
ui.benchmarks[0].setup = function() {
console.log("setup[0]");
observer.observe(haystack, {
childList: true,
subtree: true
});
};
var style = document.createElement('style');
style.innerHTML = document.getElementById('style-template').innerHTML;
ui.benchmarks[1].setup = function() {
console.log("setup[1]");
document.body.appendChild(style);
haystack.addEventListener("animationstart", animationListener, false);
haystack.addEventListener("MSAnimationStart", animationListener, false);
haystack.addEventListener("webkitAnimationStart", animationListener, false);
j = 0;
};
ui.benchmarks[2].setup = function() {
console.log("setup[2]");
haystack.addEventListener("DOMNodeInserted",
nodeInsertedListener, false);
j = 0;
};
ui.benchmarks[0].teardown = function() {
console.log("teardown[0]");
observer.disconnect();
haystack.innerHTML = "";
};
ui.benchmarks[1].teardown = function() {
console.log("teardown[1]");
document.body.removeChild(style);
haystack.removeEventListener("animationstart", animationListener, false);
haystack.removeEventListener("MSAnimationStart", animationListener, false);
haystack.removeEventListener("webkitAnimationStart",
animationListener, false);
haystack.innerHTML = "";
j = 0;
};
ui.benchmarks[2].teardown = function() {
console.log("teardown[2]");
haystack.removeEventListener("DOMNodeInserted",
nodeInsertedListener, false);
haystack.innerHTML = "";
j = 0;
};
</script>
Ready to run.
Test | Ops/sec | |
---|---|---|
MutationObserver |
| ready |
CSS Animations |
| ready |
Mutation Events (DOMNodeInserted) |
| ready |
You can edit these tests or add more tests to this page by appending /edit to the URL.