Last active
December 29, 2015 04:09
-
-
Save treelite/7612977 to your computer and use it in GitHub Desktop.
nextTick
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @file nextTick | |
* @author treelite(c.xinle@gmail.com) | |
*/ | |
define(function () { | |
var res; | |
var Observer; | |
var callbacks = []; | |
var attributeName = 'promise'; | |
function handler(mutations) { | |
var item = mutations[0]; | |
if (item.attributeName == attributeName) { | |
var len = callbacks.length; | |
for (var i = 0; i < len; i++) { | |
callbacks[i](); | |
} | |
callbacks.splice(0, i); | |
} | |
} | |
// for node or IE 10 | |
// https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/setImmediate/Overview.html#processingmodel | |
if (typeof setImmediate == 'function') { | |
res = setImmediate; | |
} | |
// for modern browser | |
// http://caniuse.com/#search=mutationobserver | |
else if (Observer = window.MutationObserver | |
|| window.webKitMutationObserver | |
) { | |
var observer = new Observer(handler); | |
var ele = document.createElement('div'); | |
observer.observe(ele, {attributes: true}); | |
res = function (fn) { | |
callbacks.push(fn); | |
ele.setAttribute( | |
attributeName, | |
Date.now ? Date.now() : (new Date()).getTime() | |
); | |
}; | |
} | |
// for node older version | |
else if (typeof process == 'object' && process.nextTick) { | |
res = process.nextTick; | |
} | |
// for older browser | |
else { | |
res = function (fn) { | |
setTimeout(fn, 0); | |
}; | |
} | |
return res; | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8" /> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no" /> | |
<title>NextTick - Performance Test</title> | |
<style> | |
#logger { | |
border: 1px solid #CCC; | |
padding: 5px; | |
} | |
#logger p { | |
border-bottom: 1px solid #CCC; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="logger"></div> | |
<script> | |
function blank () {} | |
function log(text) { | |
var ele = document.getElementById('logger'); | |
var p = document.createElement('p'); | |
p.innerHTML = text; | |
ele.appendChild(p); | |
} | |
function callback(list) { | |
var len = list.length; | |
for (var i = 0; i < len; i++) { | |
list[i](); | |
} | |
list.splice(0, len); | |
} | |
var nextTick = (function () { | |
var callbacks = []; | |
var attributeName = 'x'; | |
var Observer = window.MutationObserver | |
|| window.webKitMutationObserver; | |
if (!Observer) { | |
return blank; | |
} | |
var observer = new Observer(function (mutations) { | |
var item = mutations[0]; | |
if (item.attributeName == attributeName) { | |
callback(callbacks) ; | |
} | |
}); | |
var ele = document.createElement('div'); | |
observer.observe(ele, {attributes: true}); | |
return function (fn) { | |
callbacks.push(fn); | |
ele.setAttribute(attributeName, Date.now()); | |
}; | |
})(); | |
var setZeroTimeout = (function () { | |
var messageName = 'timeout'; | |
var callbacks = []; | |
window.addEventListener( | |
'message', | |
function (e) { | |
if (e.source == window | |
&& e.data == messageName | |
) { | |
callback(callbacks); | |
} | |
}, | |
false | |
); | |
return function (fn) { | |
callbacks.push(fn); | |
window.postMessage(messageName, '*'); | |
}; | |
})(); | |
var messageChannel = (function () { | |
var callbacks = []; | |
if (typeof window.MessageChannel !== 'function') { | |
return blank; | |
} | |
var channel = new MessageChannel(); | |
channel.port2.onmessage = function () { | |
callback(callbacks); | |
}; | |
return function (fn) { | |
callbacks.push(fn); | |
channel.port1.postMessage('*'); | |
}; | |
})(); | |
var max = 1000; | |
var sum; | |
var last; | |
function test(nextTick, index) { | |
last = Date.now(); | |
nextTick(function () { | |
var now = Date.now(); | |
sum += now - last; | |
if (++index < max) { | |
test(nextTick, index); | |
} | |
else { | |
log('sum: ' + sum); | |
log('repeat: ' + max); | |
log('avg: ' + sum / max); | |
runNextSpec(); | |
} | |
}); | |
} | |
var testIndex = 0; | |
var speces = []; | |
function addSpec(spec) { | |
if (spec.detect()) { | |
speces.push(spec); | |
} | |
else { | |
log('this browser do not support ' + spec.name); | |
} | |
} | |
function runNextSpec() { | |
var spec = speces[testIndex++]; | |
if (!spec) { | |
return; | |
} | |
log('test ' + spec.name + ' ...'); | |
sum = 0; | |
index = 0; | |
test(spec.nextTick, 0); | |
} | |
addSpec({ | |
name: 'requestAnimationFrame', | |
detect: function () { return typeof window.requestAnimationFrame == 'function'; }, | |
nextTick: function (fn) { window.requestAnimationFrame(fn); } | |
}); | |
addSpec({ | |
name: 'setTimeout', | |
detect: function () { return true; }, | |
nextTick: function (fn) { setTimeout(fn); } | |
}); | |
addSpec({ | |
name: 'postMessage', | |
detect: function () { return typeof window.postMessage == 'function'; }, | |
nextTick: setZeroTimeout | |
}); | |
addSpec({ | |
name: 'MessageChannel', | |
detect: function () { return typeof window.MessageChannel == 'function'; }, | |
nextTick: messageChannel | |
}); | |
addSpec({ | |
name: 'MutationObserver', | |
detect: function () { return !!(window.MutationObserver || window.webKitMutationObserver) }, | |
nextTick: nextTick | |
}); | |
runNextSpec(); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment