%username%
! A small study on "what way to put a function / method for processing in a queue more efficiently" and, as a result, a comparative test, and the final implementation of a function similar to setImmediate
. This method is necessary for those who want to break the execution of the script so that it does not “hang” the browser, which can be useful with a huge initialization script, parsing a large amount of data, building a complex structure without resorting to WebWorkers.
setImmediate
is a method of a window
object that should call a function passed to it asynchronously, such a setTimeout(fn, 0)
, where 0 is actually 0, not at least 4. For nodejs programmers, this is process.nextTick
. Since the method itself (setImmediate) has a clear standard with errors and additional parameters; consider the abstract task of asynchronous execution of the passed function / method as quickly as possible .
MutationObserver
) in the list, because they are strongly recommended to avoid in product versions of software. Looking ahead: lie. Let's conduct research of four methods: setTimeout
, postMessage
, Promise
, MutationObserver
.
nextTick
way to implement nextTick
? Yes, through the same setTimeout(fn, 0)
. (hehe, as done here , either from ignorance about process.nextTick
or from the old version of node)
var nextTick, nextTickTO; nextTickTO = function() { var call // , queue // , i // , fire // , nextTick // ; i = 0; queue = new Array(16); // fire = false; call = function() { // ? var len, s, track; // , track = queue; // len = i; // .. queue.length 16 s = 0; // queue = new Array(16); // i = 0; // fire = false; while (s < len) { track[s++](); // : } }; nextTick = function(fn) { queue[i++] = fn; if (!fire) { fire = true; setTimeout(call, 0); } }; return nextTick; }; nextTick = nextTickTO();
queue
immediately of a certain size, so that the speed of allocating memory for arrays on different engines does not affect research), a pointer ( i
, at the same time an indicator of the array length), a call
method that will “go through” by array, indicator ( fire
), that the asynchronous start method is called by the producer himself in the nextTick
, which is returned.
postMessage
( here or for example here ), and it is much faster and you could calm down, but everything changes when you really need a very fast nextTick
and considering the growth of the mobile device market, the need for optimization is enormous.
nextTickPM = function() { var fire, i, nextTick, queue; i = 0; queue = new Array(16); fire = false; window.onmessage = function(message) { // call var data, len, s, track; data = message.data; if (data === 'a') { // - ? ? track = queue; len = i; s = 0; queue = new Array(16); i = 0; fire = false; while (s < len) { track[s++](); } } }; nextTick = function(fn) { queue[i++] = fn; if (!fire) { fire = true; postMessage('a', '*'); } }; return nextTick; };
postMessage
? It affects a huge message transfer system, checks on domain names, checks on transmitted values, setting in separate message queues. The rest is a sharor beaver.
Promises
), deciding that it was possible and faster, and he was right.
nextTickPR = function() { var call, fire, i, nextTick, p, queue, s; if (typeof Promise === "undefined" || Promise === null) { return nextTickMO(); } i = 0; r = 0; // call queue = new Array(16); fire = false; p = Promise.resolve(); call = function() { var len, s, track; track = queue; len = i; s = 0; queue = new Array(16); i = 0; fire = false; while (s < len) { track[s++](); } if ((r++) % 10 === 0) { // p = Promise.resolve(); } }; nextTick = function(fn) { queue[i++] = fn; if (!fire) { fire = true; p = p.then(call); } }; return nextTick; };
call
( r
) and select the new Promise.resolve()
every 10 calls. Perhaps a different number will do, but later, as we shall see, you can throw these lines to the line (the evil one already has the setImmediate standard and the call counter).
MutationObserver
), callbacks are called asynchronously in them, Node
elements have (HTMLElement is an instance of Node) setAttribute
method, which programmers, without hesitation, will associate the same with direct queuing, without unnecessary verification systems, like a messaging system. It is not recommended to use for full-fledged nodes that are already built into the DOM, but what if we don’t embed in the DOM and neatly live the node in closures? As it turned out so.
nextTickMO = function() { var a, fire, i, nextTick, observer, queue, s; i = 0; r = 0; // queue = new Array(16); fire = false; a = document.createElement('a'); // observer = new MutationObserver(function() { // call var len, s, track; track = queue; len = i; s = 0; queue = new Array(16); i = 0; fire = false; while (s < len) { track[s++](); } }); observer.observe(a, { // attributes: true, attributeFilter: ['lang'] }); nextTick = function(fn) { queue[i++] = fn; if (!fire) { fire = true; a.setAttribute('lang', (r++).toString()); } }; return nextTick; };
Source: https://habr.com/ru/post/275023/