Приветствую.
На самом деле, речь не совсем о трединге. Да, в Javascript «чистого» трединга вроде как нету, но есть ещё webworkers, это я знаю, а здесь я хочу поднять вопрос о другом. Для начала я уточню, что конкретно я буду подразумевать под «тредингом».
Типичная задача следующая. Есть некий код (для определённости, врапнутый в функцию myFunc) и я хочу запустить этот код неким вызовом, но при этом не дожидаясь завершения этого вызова перейти к следующей строке кода, откуда я этот вызов совершаю. Обычно эта задача решается примерно таким образом:
setTimeout( myFunc, 10 );
doSomethingElse();
где myFunc() содержит код, который я хочу выполнить «в треде», а doSomethingElse() содержит код, про который я хочу чтобы он начал выполняться, не дожидаясь завершения myFunc(). А если мне нужно вызвать функцию myFunc() как метод объекта — я могу заюзать замыкание и apply(), обернув это в ещё одну анонимную функцию.
Самое загадочное в таком подходе — второй аргумент функции setTimeout(). Почему я сказал ей выполнить код через 10 милисекунд, а не сразу — через 0?
Люди пишут (комменты), что setTimeout(fn, 0) часто работает дольше, чем setTimeout(fn, 10). И там же предлагается ещё более быстрый способ «заказать» асинхронное выполнение функции «прямо сейчас», с использованием postMessage.
Я решил немного поэкспериментировать с приведённым там кодом и сделать его чуть более удобным. Идея состоит в том, что прототипу объекта типа Function добавляется новый метод thread(), который запускает эту функцию асинхронно и форвардит ей все аргументы. Получилось примерно так:
(function() {
var threads = [];
var messageName = "start-thread";
function thread(fn) {
threads.push(fn);
window.postMessage(messageName, "*");
}
function startThread(event) {
if (event.source == window &&
event.data == messageName) {
event.stopPropagation();
if (threads.length> 0) {
( threads.shift() )();
}
}
}
window.addEventListener("message", startThread, true);
Function.prototype.thread = function() {
var args = arguments;
var me = this;
thread(
function() {
me.apply( null, args );
}
);
}
})();
var doSomething = function(a, b) {
alert( a + b );
}
// вызываем doSomething() асинхронно:
doSomething.thread( 2, 3 );
В общем, это практически точная копия кода по ссылке, плюс новый метод thread объектам типа Function.
И теперь внимание вопрос. Для того, чтобы метод thread был действительно удобным, нужно иметь возможность использовать его для методов объектов. То есть, каким-то образом в функцию thread нужно «протащить» информацию об объекте, в контексте которого мы обратились к методу. Использование замыкания напрочь испортит всю элегантность. Хочется пользоваться этим методом примерно так:
myObject.myMethod.thread( arg1, arg2 );
и в результате такого вызова метод myMethod должен вызваться асинхронно в контексте объекта myObject, то есть должно произойти
myObject.myMethod.apply( myObject, [ arg1, arg2 ] );
Возможно ли это?