19.03.2014, 17:21
|
|
|
Регистрация: 10.07.2008
Сообщений: 3,873
|
|
Асинхронный вызов функций
Посоветуйте, какой из вариантов реализации 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 не рассматриваю, так как не устраивает скорость выполнения.
Последний раз редактировалось Octane, 23.03.2014 в 14:59.
|
|
19.03.2014, 18:01
|
|
junior
|
|
Регистрация: 29.11.2011
Сообщений: 3,924
|
|
Сообщение от Octane
|
Третий вариант с использованием setTimeout не рассматриваю, так как не устраивает скорость выполнения.
|
поясни
http://stackoverflow.com/a/9516967
__________________
Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук
|
|
19.03.2014, 18:39
|
|
|
Регистрация: 10.07.2008
Сообщений: 3,873
|
|
Сообщение от nerv_
|
поясни
|
у setTimeout есть минимальная задержка 3-5 мс, передавать 0 бесполезно
|
|
19.03.2014, 19:00
|
|
junior
|
|
Регистрация: 29.11.2011
Сообщений: 3,924
|
|
Сообщение от Octane
|
у setTimeout есть минимальная задержка 3-5 мс, передавать 0 бесполезно
|
это понятно
Если функция вызывается асинхронно, то время, когда именно она будет вызвана может варьироваться и зависит от ряда факторов. О какой скорости может идти речь в этом случае, я не понимаю
В первом варианте заменил alert() на console.log(), в хроме получилось синхронно.
__________________
Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук
|
|
19.03.2014, 19:04
|
|
|
Регистрация: 10.07.2008
Сообщений: 3,873
|
|
Тесты на скорость выполнения:
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);
}
});
Последний раз редактировалось Octane, 23.03.2014 в 15:00.
|
|
29.03.2014, 01:17
|
|
junior
|
|
Регистрация: 29.11.2011
Сообщений: 3,924
|
|
__________________
Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук
|
|
30.03.2014, 04:11
|
|
|
Регистрация: 10.07.2008
Сообщений: 3,873
|
|
Есть идеи, почему у первого варианта в 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;
};
а этот вариант нормально работает
|
|
|
|