Притча о перехвате ошибок

    — Здравствуй, дружок. Хочешь, я расскажу тебе сказку? }:-]
    — Конечно, дяденька, а какую? *_*
    — Я расскажу тебе как делают детей ^_^'
    — ого, как интересно! @_@
    — Так вот, слушай. Дети появляются вследствие долгого и изнуряющего процесса разной степени нецензурности. Сейчас я поведаю тебе как появился на свет мой сын %-)
    — А вы меня с ним познакомите? *о*
    — Не торопи события. Обо всём по порядку. Однажды я наваял такой код:
    1. try {
    2.     throw new Error
    3. } catch( e ){
    4.     if( e != false ) throw e
    5. }
    — А что он делает? о_0
    — Не важно, главное, тут другое, а именно то, что только Опера и Мозилла в консоли ошибок указали на вторую строку скрипта. Хром указал на четвёрную, а Ишак вообще на третюю .-.
    — Ну и что с того? ._.
    — А то, что использование таких конструкций перепосылки исключений в общем случае приводит к тому, что исключения теряют свои координаты и становятся совершенно бесполезными при отладке. Мы знаем, что произошла ошибка, даже знаем какая, но только методом научного тыка можем установить где она произошла. Кроме того, в некоторых отладчиках есть полезная функция перехода в режим пошаговой отладки в случае возникновения ошибки… Догадайся, в каком месте произойдёт остановка исполнения т_т
    — Тогда надо не делать так и всё будет хорошо! \(^_^)/
    — Хех, если бы всё было так просто… К сожалению во всех популярных фреймворках встречаются подобные выкрутасы, причём во многих случаях ошибки просто сглатываются :-\
    — Так не используйте их и все дела! =)
    — Пхах! Наивный маленький мальчик! Это невозможно… по разным причинам… =(
    — Почему? А что ещё остаётся-то? о0'
    — Ну, я просто пропатчил используемый нами фреймворк, вычистив все перехваты ошибок нашего приложения, правда это слегка нарушило его api =_=
    — Вау, а что вы там такого наворотили-то? 0_0
    — Ну вот, лови пример:
    1. each: function(iterator, context) {
    2.     var index = 0;
    3.     try {
    4.         this._each(function(value) {
    5.             iterator.call(context, value, index++);
    6.         });
    7.     } catch (e) {
    8.         if (e != $break) throw e;
    9.     }
    10.     return this;
    11. },
    — Что это? +_+'
    — Это функция итерирования из prototypeJS. Видно его разработчики совсем не занимались отладкой скриптов в браузерах отличных огнелиса, так как реализовали прерывание цилка именно таким образом. Не буду утомлять тебя яваскриптом — скажу лишь, что я вырезал try-catch, а во все итераторы прописал передачу дополнительного параметра, возвращение которого прерывает итерирование ^_^
    — Как всё хорошо закончилось! :-)
    — Нет, только началось… Не всегда итерирование можно просто взять и вырезать, ибо иногда требуется выполнить какой-то небезопасный код так, чтобы он не прервал выполнение нашего. Вот, лови пример из jQuery:
    1. // Trigger an inline bound script
    2. try {
    3.     if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) {
    4.         if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) {
    5.             event.result = false;
    6.         }
    7.     }
    8. // prevent IE from throwing an error for some elements with some event types, see #3533
    9. } catch (e) {}
    — Ой, а как же быть тогда-то? о_о'
    — Ну, тут я стащил немного семени Дина Эдвардса ( dean.edwards.name/weblog/2009/03/callbacks-vs-events ) и породил враппер, который выполняет некоторый кусок кода безопасно от остального, при этом ни коим образом не перехватывая исключения, а отдавая их на попечение отладчику В-]
    — Чего-чего? :-О
    — Грубо говоря, последний код можно переписать следующим образом, позвав на помощь моего сына по имени FThread:
    1. // Trigger an inline bound script
    2. // prevent IE from throwing an error for some elements with some event types, see #3533
    3. FThread( function(){
    4.     if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) {
    5.         if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) {
    6.             event.result = false;
    7.         }
    8.     }
    9. }).call( this )
    — А если не так грубо? :-[
    — М… дружок, лучше я оставлю вас на едине — он сам о себе всё красноречиво расскажет ;-)

    var FThread= new function(){<br><br>Version: 4<br>Description: 'creates a wrapper for function that allows you to not be afraid of exceptions in'<br>License: 'public domain'<br> <br>Implementation:<br><br>var scripts= document.getElementsByTagName( 'script' )<br>var script= scripts[ scripts.length - 1 ]<br>var starter= document.createElement( 'button' )<br>starter.id= 'thread starter'<br>starter.style.display= 'none'<br>script.parentNode.insertBefore( starter, script )<br><br>var FThread= function( proc ){<br>    var thread= function( ){<br>        var res, self= this, args= arguments<br>        starter.onclick= function( ev ){<br>            ( ev || event ).cancelBubble= true<br>            starter.onclick= null<br>            res= thread.proc.apply( self, args )<br>        }<br>        starter.click()<br>        return res<br>    }<br>    thread.proc= proc<br>    return thread<br>}<br><br><br>Export: return FThread<br><br>Usage:<br><br>var inverse= FThread(function( a ){<br>    if( a === -1 ) (void 0)()<br>    if( a === 0 ) throw Error( 'division by zero' )<br>    return 1/a<br>})<br>alert([ inverse( -1 ), inverse( 0 ), inverse( 1 ) ])<br>// alerts ",,1" and two exceptions in console log<br><br>}
    Поделиться публикацией
    Похожие публикации
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 36
    • 0
      >\(^_^)/
      >+_+'
      >=_=
      >В-]
      кажется, у вас проблемы с кодировкой.
      • +1
        нет, кажется у вас аллергия на смайлики :-Р
        • +3
          а-а-а! его похитило НЛО! 0_0''
          • +1
            В теме про билайн тоже кого-то похитили, не его ли :D
            • 0
              ахтунг! нашествие инопланетян! \(<>..<>)/
      • +2
        Так о чем статья-то?
        • +2
          это глубокий философский вопрос, разрешение которого сродни становлению новой формы мышления в условиях стагнирующей социальной системы, вырванной из обёртки высоколатентной комуникационной среды
        • +3
          Хабросообщество не поймет.

          Статья зачотная.
          У меня вопрос. А почему используется некий стартер? Зачем? Не проще ли было бы отделать отдельные нити с помощью setTimeout()?
          • +2
            ему же хуже ;-)

            setTimeout создаёт асинхронные нити, а FThread — синхронные. это позволяет работать с любыми функциями абсолютно прозрачно
            • +1
              А в ие проверялось? Вроде оно у меня когда-то на что-то ругалось при работе с непридомленными кнопками…

              Пойду тихонько помечтаю об асинхронном жаваскрипте :)
              • 0
                так у меня придомленная кнопка ;-)

                хочу эрланг на клиенте х)
                • +1
                  Да. Невнимательно посмотрел :)

                  Хотеть не вредно. Вредно не хотеть. Может и дорастет веб до этого. Прожуем — увидим, как говорится.
                • +1
                  WebWorkers в HTML5, не?
                  • +1
                    Тык да. Но пока они еще в массы проберутся…

                    /me пошел допиливать скрипты под ие6
                    • +1
                      У WebWorker много ограничений: он должен жить в отдельном файле, файл должен находиться на том же домене, worker не имеет доступа ни к DOM, ни к остальным скриптам, общение с внешним миром только с помощью XMLHttpRequest или postMessage.
                      • +1
                        Дык, а вы хотите кучу геморроя с синхронизацией потоков? Первые два ограничения конечно спорны имхо, но вот ограничение на доступ к DOM, и общение через сообщения это имхо верная стратегия. Как минимум это избавляет от проблем с синхронизацией.
                        • +1
                          Полностью с вами согласен. Я лишь говорю, что WebWorkers предназначены для узкого круга задач.
                          • 0
                            я так понимаю там кооперативные потоки как в setTimeout
                          • 0
                            а из примеров видно что доступ к дому есть
                        • 0
                          очень похоже, только некроссбраузерно, требует множить файлы, неудобно использовать и нельзя использовать как обычную функцию
                  • +2
                    Такой вопрос — в приведенном вами коде что за странные дополнения?
                    Скажем Implementation: Export: — что это и откуда берется? Ни разу не сталкивался с таким оформлением кода.
                    • +1
                      это метки позволяющие структурировать код %-) в общем случае можно использовать любые свободные имена
                    • +1
                      Было бы круто получить dom-независимое решение
                      • +1
                        ещё бы %-) а те зачем именно независимость от дома?
                        • +1
                          Самое главное — для удовлетворения. Ну и IE может не дать приаттачить элемент пока дерево не загрузится.
                          • +1
                            не может
                            • +1
                              Смотря куда будет аттачиться и когда аттач будет производиться, сейчас кейс не вспомню, но суть примерно такова
                              • +1
                                только если в конец
                      • +1
                        Пока что получилось только решение с XHR, как лучше всего проверить синхронность?
                      • 0
                        ну, если так отрабатывает нормально, то всё пучком: alert([ inverse( -1 ), inverse( 0 ), inverse( 1 ) ])
                        • +1
                          Ну нормально ага, у меня правда немного по другому реализован сам вызов, но внутри тупо на .onreadystatechange вешаем нужный колбэк и загружаем тупо #якорь. Проверил: повторно документ не загружает, но надо будет с разными условиями кеширования проверить конечно

                      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.