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, время: 07:51. |