| 
	| 
	
	| 
		
	| 
			
			 
			
				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;
};
а этот вариант нормально работает
			
			
	
			
			
			
			
			
				  |  |  |  |