Асинхронный вызов функций
Посоветуйте, какой из вариантов реализации setImmediate выбрать для асинхронного вызова функций?
Первый вариант: var callAsync = function () { var fakeNode = document.createElement("img"), storage = {}, uid = 0; fakeNode.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=="; fakeNode.style.cssText = "position: absolute; top: -9999px; left: -9999px; width: 0; height: 0;"; document.body.appendChild(fakeNode); fakeNode.addEventListener("load", function (event) { var key = event.key, data = storage[key]; data.callback.call(data.thisObj, data.data); delete storage[key]; }); return function (callback, thisObj, data) { var key = "call" + uid++; storage[key] = { data: data, thisObj: thisObj, callback: callback }; var event = document.createEvent("HTMLEvents"); event.initEvent("load", false, false); event.key = key; fakeNode.dispatchEvent(event); }; }(); callAsync(function () { throw Error("test"); }); alert("done");В этом варианте, мне не нравится, что лишний <img> будет все время находится на странице, попадать в коллекции или мешать какому-нибудь nth-child. А если кому-нибудь вздумается скрипт в <head> засунуть, то придется еще и DOMContentLoaded добавлять для всего, что будет использовать callAsync. Второй вариант: var message = "ServiceMessage", storage = {}, uid = 0; addEventListener("message", function (event) { var key = event.data, data; if (typeof key == "string" && key.indexOf(message) == 0) { data = storage[key]; data.callback.call(data.thisObj, data.data); delete storage[key]; } }); function callAsync(callback, thisObj, data) { var key = message + uid++; storage[key] = { data: data, thisObj: thisObj, callback: callback }; postMessage(key, "*"); } callAsync(function () { throw Error("test"); }); alert("done");В этом варианте боюсь, что постоянный флуд в message кому-нибудь навредит. Третий вариант с использованием setTimeout не рассматриваю, так как не устраивает скорость выполнения. |
Цитата:
http://stackoverflow.com/a/9516967 |
Цитата:
|
Цитата:
Если функция вызывается асинхронно, то время, когда именно она будет вызвана может варьироваться и зависит от ряда факторов. О какой скорости может идти речь в этом случае, я не понимаю :) В первом варианте заменил alert() на console.log(), в хроме получилось синхронно. |
Тесты на скорость выполнения:
var intervals = [], i = 100, t1 = Date.now(), t2; setTimeout(function () { t2 = Date.now(); intervals.push(t2 - t1); t1 = t2; if (i--) { setTimeout(arguments.callee, 0); } else { alert(intervals); } }, 0); var message = "ServiceMessage", storage = {}, uid = 0; addEventListener("message", function (event) { var key = event.data, data; if (typeof key == "string" && key.indexOf(message) == 0) { data = storage[key]; data.callback.call(data.thisObj, data.data); delete storage[key]; } }); function callAsync(callback, thisObj, data) { var key = message + uid++; storage[key] = { data: data, thisObj: thisObj, callback: callback }; postMessage(key, "*"); } var intervals = [], i = 100, t1 = Date.now(), t2; callAsync(function () { t2 = Date.now(); intervals.push(t2 - t1); t1 = t2; if (i--) { callAsync(arguments.callee); } else { alert(intervals); } }); |
|
Есть идеи, почему у первого варианта в IE8 длина стека вызовов всего 5?
/** * setImmediate polyfill */ window.setImmediate || new function () { var id = 0, storage = {}, message = "setImmediatePolyfillMessage"; function fastApply(args) { var func = args[0]; switch (args.length) { case 1: return func(); case 2: return func(args[1]); case 3: return func(args[1], args[2]); } return func.apply(window, Array.slice(args, 1)); } function callback(event) { var key, data; event = event || window.event; key = event.data; if (typeof key == "string" && key.startsWith(message)) { data = storage[key]; if (data) { fastApply(data); delete storage[key]; } } } function setImmediate() { var key = message + ++id; storage[key] = arguments; postMessage(key, "*"); return id; } function clearImmediate(id) { delete storage[message + id]; } addEventListener("message", callback, false); window.setImmediate = setImmediate; window.clearImmediate = setImmediate; }; пробовал arguments преобразовывать в массив, не помогает, 6-й рекурсиный вызов приводит к stack overflow /** * IE8 setImmediate polyfill */ document instanceof Object || new function () { var root = document.documentElement, fakeScript = document.createElement("script"); //todo code reuse function fastApply(args) { var func = args[0]; switch (args.length) { case 1: return func(); case 2: return func(args[1]); case 3: return func(args[1], args[2]); } return func.apply(window, Array.slice(args, 1)); } function setImmediate () { var args = arguments, tmpScript = fakeScript.cloneNode(false); tmpScript.onreadystatechange = function () { fastApply(args); tmpScript.onreadystatechange = null; root.removeChild(tmpScript); tmpScript = null; }; root.appendChild(tmpScript); return 0; } function clearImmediate() {} window.setImmediate = setImmediate; window.clearImmediate = setImmediate; };а этот вариант нормально работает |
Часовой пояс GMT +3, время: 09:40. |