7

每当事件处理程序内部发生错误时,它会完全停止代码执行,因此不会调用第二个事件回调。

例如:

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

您可以通过在两个匿名函数中添加 try/catch 来轻松解决此(简化)示例中的问题,但实际上这些函数通常会添加几个其他事件处理程序,而这些事件处理程序又需要 try/catch。我最终得到了非常重复的代码,里面塞满了 try/catch 块。

我的项目采用模块化设计,其中每个功能都位于不同的 JS 中(并在构建过程中连接起来)。我正在寻找一种更通用的方法来处理每个功能内部的错误,以便错误不会停止其他功能的代码执行。

我已经尝试了以下解决方案: - window.onerror(即使您在此函数中返回 true,代码执行也会停止) - $(window).error() => 已弃用并且代码执行停止

4

5 回答 5

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);
    });
});

我创建了一个小演示。它略有不同,但想法相同。

于 2013-05-24T07:30:19.583 回答
0

我会用一个包装器来尝试这样的事情,它会为你处理try catch(见下文,或者这个jsfiddle:http: //jsfiddle.net/TVfCj/2/

从我(不是,也不是真的)处理this和参数的方式来看,我想很明显我是从 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');
于 2013-05-24T09:33:11.920 回答
0

您可以在调用if (typeof myFunction == 'function')之前简单地调用myFunction()

并且可以选择将其包装在 Bart 所说的通用函数中,如果您的函数不存在,则可以选择在控制台中记录错误。

如果你的 webapp 很大,有很多交互和 JS,太多try catch可能会改变你的应用程序的全局性能。

于 2013-05-24T07:52:28.970 回答
0

您在问题中提到尝试的try-catch模式是正确的方式 - 您想要 try-catch块,而不是静默通过模块错误的方式(通常总是非常小心地处理全局异常并继续,这样就存在您只会发现的数据损坏错误6 个月后)。

你真正的问题是这样的:

...实际上,这些函数通常会添加几个其他事件处理程序,而这些事件处理程序又需要 try/catch。我最终得到了非常重复的代码,里面塞满了 try/catch 块。

解决方法是Promise. 这是一种新结构,在大多数浏览器中都是原生的,但在慢速浏览器(嗯,IE)中很容易填充,它为您提供了一种管理事件回调事件异常的标准方法。

使用 aPromise您的代码承诺总是做某事:解决/成功或拒绝/失败。

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

这更好,因为您可以将 promise 链化,而不是在每个回调中嵌套trycatch

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块,但是任何被包装在 a 中的东西都Promise可以以相同的模块化方式处理。

JS 中的下一个是asyncand await,但您现在可以将它们与转译器一起使用。这些使用承诺使代码更易于阅读,最重要的是(对您而言)在顶部有一个单一的try-用于从整个链中收集异常。catchPromise

这个答案已经太长了,但我已经在博客上更详细地介绍了

TL;DR:如果您的问题是“非常重复的 [事件回调] 代码中塞满了 try/catch 块”,请尝试Promise改用。

于 2017-02-27T09:27:27.420 回答
-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/

于 2013-07-14T19:34:58.797 回答