2013-05-24 2 views
6

Всякий раз, когда ошибка возникает внутри обработчика события, он полностью прекращает выполнение кода, поэтому вызов второго события не вызывается.Ошибка Javascript останавливает выполнение кода

Например:

$(function() { 
    window.thisDoesntExist(); 
} 
$(function() { 
    //Do something unharmful and unrelated to the first event 
} 

Вы можете легко решить эту проблему в этом (упрощенном), например, путем добавления TRY/поймать в обеих анонимных функций, но в действительности эти функции часто добавляют несколько других обработчиков событий, которые, в свою очередь потребует try/catch. Я получаю очень повторяющийся код, заполненный блоками try/catch.

Мои проекты имеют модульную конструкцию, где каждая функция находится в другом JS (и получает сцепление в процессе сборки). Я ищу более общий способ обработки ошибок внутри каждой функции, чтобы ошибка не прекращала выполнение кода другими функциями.

Я уже пробовал следующие решения: - window.onerror (даже если вы возвращаете верно в этой функции, выполнение кода останавливается) - $ (окно) .error() => осуждается и выполнение кода останавливается

+0

Вы прочитали мой вопрос? Вы можете легко решить проблему в этом (упрощенном) примере, добавив try/catch в обе анонимные функции, но на самом деле эти функции часто добавляют несколько других обработчиков событий, которые, в свою очередь, потребуют try/catch. Я получаю очень повторяющийся код, заполненный блоками try/catch. – Webberig

+0

Ну, может быть, это компромисс, который вы должны сделать, если хотите, чтобы ваш код был настолько прочным, насколько это возможно. – CBroe

+0

@Webberig, обязательно сделаю. Основное требование, которое вам нужно, - продолжить выполнение кода (любой) ошибки. Единственный способ - использовать try catch. Это первый шаг. После этого вы можете использовать обратный вызов ошибки или исправить событие ошибки или что-то еще, чтобы сделать вашу обработку ошибок прочной и гибкой. Вы можете ссылаться на исходный код Requirejs, он также использует try catch. https://github.com/jrburke/requirejs/blob/master/require.js –

ответ

-2

Я нашел решение. При использовании setTimeout код выполняется в отдельном потоке, поэтому он не будет разбивать другие части веб-страницы.

$(function() { 
    setTimeout(function() { 
    window.thisDoesntExist(); 
    }, 0); 
}); 
$(function() { 
    setTimeout(function() { 
     //Do something unharmful and unrelated to the first event 
     alert("This passes") 
    }, 0); 
}); 

В этом примере вторая функция запускается, даже когда первая вызывает ошибку. Вот рабочий пример: http://jsfiddle.net/mathieumaes/uaEsy/

+1

+1, потому что я что-то узнал -1, потому что это супер грубый взлом – mpd

+2

Функция setTimout для ссылок не работает в отдельном потоке. Стол выполнения среды выполнения JavaScript является однопоточным. На самом деле происходит то, что когда ваша ошибка обрабатывается вашим обратным вызовом onerror, стек выполнения очищается (поэтому после ошибки не запускается дополнительный код).setTimeout приводит к тому, что ссылочная функция помещается в очередь событий и события в этой очереди, когда стек выполнения очищен. Он работает, но не из-за многопоточности. – user1739635

+0

Кроме того, заказ не гарантируется при запуске async, зависит от реализации, если эти задачи должны выполняться последовательно, вы будете создавать условия гонки. Я полагаю из контекста, что порядок здесь не имеет значения, а как общее решение, это проблематично. – guioconnor

5

Вы можете создать вспомогательную функцию для предотвращения дублирования одного и того же кода шаблона.

function tryFunction(f, onerror) { 
    try { 
     if (typeof f == 'function') { 
      return f(); 
     } 
    } catch (e) { 
     return onerror(e); 
    } 
} 

$(function() { 
    var result = tryFunction(window.thisDoesNotExist, function (error) { 
     alert('Whoops: ' + error); 
    }); 
}); 

I created a little demonstration. Это немного отличается, но та же идея.

0

Вы можете просто позвонить if (typeof myFunction == 'function') перед вызовом myFunction()

И необязательно завернуть его в общей функции, как сказал Барт иметь выбор для входа ошибки в консоли, если ваша функция не существует.

Если ваш webapp огромен с большим количеством взаимодействия и JS, слишком много try catch может изменить глобальную производительность вашего приложения.

0

Я хотел бы попробовать что-то вроде этого с оберткой, которая будет обрабатывать попробовать поймать для вас (см ниже, или это jsfiddle: http://jsfiddle.net/TVfCj/2/)

От того, как я нахожусь (не так, и не совсем) я работат это и аргументы, я думаю, это очевидно, что я начинаю с js. Но я надеюсь, что вы получите эту идею, и это правильно/полезно.

var wrapper = { 
     wrap: function wrap(f) { 
      return function (args) { 
       try { 
        f.apply(null, args); 
       } catch (ex){ 
        console.log(f.name+" crashed with args "+args); 
       }; 
      }; 
     } 
    }; 

    var f1 = function f1Crashes(arg) { 
     return window.thisDoesntExist(); 
    }; 
    var f2 = function f2Crashes(arg) { 
     return window.thisDoesntExist(); 
    }; 

    var f3 = function f3MustNotCrash(arg) { 
     wrapper.wrap(f1)(arg); 
     wrapper.wrap(f2)(arg); 
    } 

    f3('myarg'); 
0

try - catch шаблон, который вы упоминаете попытку в вашем вопросе правильный путь - вы хотитеtry - catch блоков, не пути к беззвучно грузовику через ошибку модуля (в общем всегда будьте предельно осторожны в обработке исключений во всем мире и продолжаете, таким образом, это ошибки с повреждением данных, которые вы найдете только через 6 месяцев).

Ваша реальная проблема заключается в следующем:

... на самом деле эти функции часто добавляют несколько других обработчиков событий, которые, в свою очередь, потребовало бы попробовать/поймать. Я получаю очень повторяющийся код, заполненный блоками try/catch.

Исправить это Promise. Это новая структура, встроенная в большинство браузеров, но легко подмешанная в медленных (ах, IE), которая дает вам стандартный способ управления как обратным вызовом события , так и исключением из события.

С кодом Promise ваш код дает обещание всегда что-то делать: разрешать/удалять или отклонять/терпеть неудачу.

function moduleA() { 
    return new Promise(function (resolve, reject) 
    { 
     try{ 
      var result = window.thisDoesntExist(); 
      resolve(resolve); // Success! 
     } 
     catch(err){ 
      reject(err); // Fail! 
     } 
    }); 
} 

Это лучше, потому что, а не гнездо try - catch блоков в каждом обратном вызове вы можете вместо цепи обещает:

moduleA(). 
    then(moduleB). 
    then(moduleC). 
    catch(errorHandler); // Catch any error from A, B, or C 

Вы также можете обрабатывать ошибку и продолжить:

moduleA(). 
    catch(continuableErrorHandler). // Catch any error from A 
    then(moduleB). 
    then(moduleC). 
    catch(errorHandler); // Catch any error from B or C 

Вам все равно понадобится много блоков try - catch в обратных вызовах, но все, что было обернуто в Promise можно обрабатывать одним и тем же модульным способом.

Следующее в JS - async и await, но вы можете использовать их сейчас с транспилером. Они используют обещания сделать код, который намного легче читать, а главное (для вас) имеют один try - catch наверху, который собирает исключения из цепочки Promise.

Этот ответ уже слишком длинный, но у меня есть blogged about that in more detail.

TL; DR: Если ваша проблема «очень повторяющийся [обратный вызов события] код фаршированной попытки/улов блоков» попробуйте использовать Promise вместо этого.

Смежные вопросы