FThread, исполнение функций в отдельных потоках
Фабрика, создающая обёртку, которая запускает функцию в отдельном потоке в результате чего её падение не приводит к падению запустившего её кода. потоки не параллельны!
var FThread= new function(){
Version: 3
Descr: 'creates a wrapper for function that allows you to not be afraid of exceptions in'
License: 'public domain'
Implementation:
var root= document.documentElement
var FThread= function( proc ){
var thread= root.addEventListener
? function( ){
var res, self= this, args= arguments
root.addEventListener( 'launch thread', function( ){
root.removeEventListener( 'launch thread', arguments.callee, false )
res= thread.proc.apply( self, args )
}, false )
var event= document.createEvent( 'UIEvents' )
event.initEvent( 'launch thread', false, false )
root.dispatchEvent( event )
return res
}
: function( ){
var res, self= this, args= arguments
root.attachEvent( 'onpropertychange', function( ){
root.detachEvent( 'onpropertychange', arguments.callee )
delete root[ 'launch thread' ]
res= thread.proc.apply( self, args )
} )
root[ 'launch thread' ]= null
return res
}
thread.proc= proc
return thread
}
Export: return FThread
Usage:
var inverse= FThread(function( a ){
if( a === 0 ) throw 'division by zero'
return 1/a
})
console.log([ inverse( 0 ), inverse( 1 ) ])
// prints [ undefined, 1 ] and exception 'division by zero' in console log
}
код не актуален ввиду новой версии: http://javascript.ru/forum/project/7...html#post44189 |
Интересно, правда не очень представляю прикладного применения.
Зато я узнал, что можно вот так вот сделать:
function A(flag) {
this.a = 1;
if(flag == 1) return {c: 3}; // typeof == "object"
if(flag == 2) return 4; // typeof != "object"
}
A.prototype.b = 2;
console.log(new A()); // {a:1, b: 2}
console.log(new A(1)); // {c: 3}
console.log(new A(2)); // {a:1, b: 2}
|
применение - независимая инициализация модулей, независимое исполнение обработчиков событий и тп
|
Цитата:
почерпнул для себя кое-что новое вот только, исключение нигде не выползает в консоль(Opera, Mozilla) Разве что, не вижу смысла зачем городить потоки для данной задачи. Сделал вот такое решение. Кто-то видит подводные камни какие?
var GThread= new function(){
//Version: 3
//Descr: 'creates a wrapper for function that allows you to not be afraid of exceptions in'
//License: 'public domain'
//Implementation:
var GThread=function(proc){
var thread=function()
{
try
{
return proc.apply(this,arguments);
}
catch(e)
{
console.warn(e);
console.trace();
return undefined;
}
}
return thread;
}
//Export: return GThread
//Usage:
var inverse=GThread(function(a){
if(a===0)
throw 'division by zero';
return 1/a;
})
var inverse2=GThread(function(a){
return -a;
})
console.log([inverse(0),inverse2(2),inverse(2)])
// prints [undefined, -2, 0.5] without( :( ) exception 'division by zero' in console log
}
|
Цитата:
|
> Сделал вот такое решение. Кто-то видит подводные камни какие?
жопа с отладкой затрайкатченного кода |
Цитата:
Opera 10.10 с активной консолью ошибок - молчок Firefox 3.5.7 с firebug-ом - молчок IE 8.0.6001 - молчок Более того результаты alert-a: Цитата:
Цитата:
Цитата:
Цитата:
Цитата:
у тебя также ни единого исключения не было проброшено кстати, ничто не мешает бросить console.error(e); поправил свой код по этому поводу |
А кто мешает сделать так ?
catch(e)
{
if (console) console.error(e);
return undefined;
}
|
PeaceCoder,
пока писал и правил свое сообщение, вы уже написали один из моих моментов))) |
гм.. что-то не то.. ща поковыряюсь..
|
Цитата:
|
фак
при вставке последовательно скрипта tenshi, а затем моего, пр пробросе в моем скрипте console.error(e); выводит сообщение из моего Exception-а, при этом давая ссылку на код скрипта tenshi Цитата:
вот только почему-то при вызове из моего скрипта backtrace ведет на ваш скрипт, чего вы так добивались))) при пробросе же console.warn(e); console.trace(); можно уивдеть корректный backtrace |
почему в ие не работает - понятно. страница в режиме совместимости видимо.
|
Цитата:
|
Цитата:
старый-добрый HTML. для своего варианта, я решил проблему с отладкой предпоследняя строчка backtrace-а в логах указывает на контекст вызова Exception также виден. решение firebug-only, поэтому не годится для отладки в других браузерах, к сожалению |
Цитата:
Ещё можно оперу прикрутить. |
Цитата:
|
пофиксил оперу
|
Вот сижу и задаюсь вопросом. Вы когда чтото пишите, Вы что пишете это всем скопом а потом запускаете в ожидании где же ошибка будет? Отлаживать код надо последовательно.
|
если бы я писал весь код сам - мне бы не пришлось патчить прототайп и вычищать оттуда трайкатч - я бы его просто не использовал х)
|
Цитата:
|
а кто прилетел вместо него?
|
Цитата:
|
хрен редьки не слаще..
|
tenshi,
может попробуешь довести свой скрипт под осла? у меня не выходит: 1)на root onpropertychange не срабатывает. зато срабатывает на document-е 2)даже если он срабатывает, то оба срабатывания происходят после вывода alert([ inverse( 0 ), inverse( 1 ) ]) то есть я не знаю, как получить res в такой ситуации |
у меня в осле работало.. правда проверял я в 8..
а вот в лисице - жопа >_<" ща попробую по другому переделать.. |
Хитрый план такой хитрый)))
не гарантирую, что это будет работать в 100% случаев/
var FThread= new function(){
//Version: 3
//Descr: 'creates a wrapper for function that allows you to not be afraid of exceptions in'
//License: 'public domain'
//Implementation:
var root= document.documentElement
var FThread= function( proc ){
var thread= root.addEventListener
? function( ){
var res, self= this, args= arguments
root.addEventListener( 'launch thread', function( ){
root.removeEventListener( 'launch thread', arguments.callee, false )
res= thread.proc.apply( self, args )
}, false )
var event= document.createEvent( 'UIEvents' )
event.initEvent( 'launch thread', false, false )
root.dispatchEvent( event )
return res
}
: function( ){
var res, self= this, args= arguments
var image=document.createElement('img');
image.onerror=function()
{
res= thread.proc.apply( self, args )
}
image.src='';//or 'about:blank'
return res
}
thread.proc= proc
return thread
}
//Export: return FThread
//Usage:
var inverse= FThread(function( a ){
if( a === 0 ) throw 'division by zero'
return 1/a
})
alert([ inverse( 0 ), inverse( 1 ) ])
// prints [ undefined, 1 ] and exception 'division by zero' in console log
}
исключение бросается уже как в опере, так и в осле. DebugBar даже начал отладку а вот в лисе, исключения не пробрасываются |
var FThread= new function(){
Version: 4
Descr: 'creates a wrapper for function that allows you to not be afraid of exceptions in'
License: 'public domain'
Implementation:
var scripts= document.getElementsByTagName( 'script' )
var script= scripts[ scripts.length - 1 ]
var starter= document.createElement( 'button' )
starter.id= 'thread starter'
starter.style.display= 'none'
script.parentNode.insertBefore( starter, script )
var FThread= function( proc ){
var thread= function( ){
var res, self= this, args= arguments
starter.onclick= function( ev ){
( ev || event ).cancelBubble= true
starter.onclick= null
res= thread.proc.apply( self, args )
}
starter.click()
return res
}
thread.proc= proc
return thread
}
Export: return FThread
Usage:
var inverse= FThread(function( a ){
if( a === -1 ) throw (void 0)()
if( a === 0 ) throw new Error( 'custom error' )
return 1/a
})
alert([ inverse( -1 ), inverse( 0 ), inverse( 1 ) ])
// alerts ",,1" and two exceptions in console log
}
исключения всплывают везде, только вот кастомные исключения теряют бэктрейс в мозилле и вообще всё в опере |
с оперой разобрался - нужно было обновить и включить: opera:config#UserPrefs|Exceptions Have Stacktrace
|
Цитата:
вторая до правки также теперь в мозилле пробрасывает. теперь вообще везде работает. красота про click хорошо придумал. для него есть гарантия, что если на протестированном браузере сработал именно так, то так будет всегда, а не зависеть от погоды, как в случае image.onerror у меня |
примечательно, что cancelBubble работает во всех браузерах
|
Сделал DOM-независимое решение:
/**
* Javascript ThreadBox
*
* DOM-independent implementation of FThread {@link http://habrahabr.ru/blogs/javascript/86852/}
*
* Usage: threadBox([context,] function);
*
* @author Vasiliy Aksyonov <outring@gmail.com>
* @version 1.0
*/
var threadBox = (function() {
var thread;
try { thread = new ActiveXObject("Msxml2.XMLHTTP"); }
catch (e) {
try { thread = new ActiveXObject("Microsoft.XMLHTTP"); }
catch (e) { thread = false; }
}
if (!thread && typeof XMLHttpRequest != 'undefined') {
thread = new XMLHttpRequest();
}
if(thread) {
var threadBox = function () {
var context = arguments.length >= 2 ? arguments[0] : null;
var process = arguments.length >= 2 ? arguments[1] : arguments[0];
thread.onreadystatechange = function() {
if (!process) {
return;
}
var innerProcess = process;
process = null;
innerProcess.call(context);
};
thread.open('GET', '#', true);
thread.send(null);
}
}
else {
var threadBox = function () {
var context = arguments.length >= 2 ? arguments[0] : null;
var process = arguments.length >= 2 ? arguments[1] : arguments[0];
try { process.call(context); }
catch(e) { setTimeout(function() { throw e; }, 0); }
}
}
return threadBox;
})();
Несмотря на то, что делаем асинхронный XMP запрос, работает вроде синхронно. Способ использования отличается конечно, но ничто не мешает переделать, но на мой взгляд (мне) так удобнее : D Ну и да, как видно добавлен небольшой костыль внизу, на всякий случай, в хроме он конечно не сильно поможет : D но хоть что-то |
ага, я попробовал с синхронным и обламался х)
|
решётку запрашивать - не вариант. ибо если не прокэшируется, то это жопа.
ещё у тебя несколько раз должна вызываться функция при каждом изменении состояния. поэтому надо удалять обработчик при первом использовании, как у меня. |
1 надо проверить, мне кажется что он пытается выполнить стандартный запрос якоря на текущей странице, как при клике на ссылку, так что тут даже вероятно и запроса то к серверу не идёт
2 выполнять 2 раза не будет, т.к. после выполнения я обnullяю process : D хотя проще было убить хэндлер, это да, затупил Как проверить проще всего? Не хочется ставить мониторов соединений никаких |
Проверил синхронность. FAIL
|
м.. не, реквесты не катят - ошибки глотаются =(
|
var FThread= new function(){
Version: 5
Description: 'creates a wrapper for function that allows you to not be afraid of exceptions in'
License: 'public domain'
Implementation:
var FThread= function( proc ){
var thread= function( ){
var res, self= this, args= arguments
var starter= new XMLHttpRequest
starter.onreadystatechange= starter.onabort= function( ev ){
starter.onreadystatechange= starter.onabort= null
res= thread.proc.apply( self, args )
}
//console.dir( starter )
starter.open( 'get', '#', true )
starter.send( null )
starter.abort()
return res
}
thread.proc= proc
return thread
}
//Export: return FThread
Usage:
var inverse= FThread(function( a ){
if( a === -1 ) (void 0)()
if( a === 0 ) throw Error( 'division by zero' )
return 1/a
})
alert([ inverse( -1 ), inverse( 0 ), inverse( 1 ) ])
// alerts ",,1" and two exceptions in console log
}
|
У меня такое наблюдается только в FF3.6, в более старых версиях ок, возможно дело в плагинах.
А с синхронностью обстоит так: в FF при синхронном запросе onreadystatechange не выполняется, а во всех остальных браузерах выполняется, но в IE всегда почему-то только один раз |
В общем всё решилось, кроме того, что FF>=3.5 проглатывает ошибки зачем то : (
Вот как поменялась функция:
var threadBox = function () {
var context = arguments.length >= 2 ? arguments[0] : null;
var process = arguments.length >= 2 ? arguments[1] : arguments[0];
thread.open('GET', '#', Array.toSource ? true : false);
thread.onreadystatechange = function () {
thread.onreadystatechange = function () { };
process.call(context);
};
thread.send(null);
}
Пока что ищу решение, как заставить ФФ не глотать : D |
| Часовой пояс GMT +3, время: 15:55. |