如何汇总JavaScript错误?

时间:2012-04-26 16:02:35

标签: javascript error-handling

在下面的代码中,我故意抛出一个错误,但在Chrome中(仅用于测试目的)它不会卷入捕获。如何将错误汇总到父级的范围内?

try {
  setTimeout(function() {
    console.log("Throwing Error...");
    throw({message:"Ouch!"});
  }, 500);
} catch(e) {
  console.log(e.message);
}

Chrome回复:

Uncaught #<Object>
  (anonymous function)

以下是我正在使用的完整示例;当我需要“bob”时(故意)超时。我想捕获requirejs错误,所以我可以使用我的应用程序的错误系统,它更健壮,通知学习者。

(function() {
try {
  var scriptVersion = "1.0.0.1"
  window.onload = function() {
    var script = document.createElement("script");
    script.type = "text/javascript";
    script.src = "//content.com/pkg/" + scriptVersion + "/require-jquery.js";
    script.async = false;
    script.done = false;
    // OnReadyStateChange for older IE browsers
    script.onload = script.onreadystatechange = function() {
      if(!(this.done) && (!this.readyState || this.readyState == "loaded" || this.readyState == "complete")) {
        this.done = true;
        require.config({
          baseUrl: "//content.com/pkg/" + scriptVersion
        });
        require(["bob"]);
      }
    }
    document.getElementsByTagName("head")[0].appendChild(script);
  }
} catch(e) {
  console.log(e);
}
})();

4 个答案:

答案 0 :(得分:6)

请参阅下面的编辑,了解如何解决requireJS的实际问题。

问题是setTimeout()函数在父作用域中运行并且没有错误地完成。它调度(使用系统)未来的回调事件,但是当将来发生回调时,父进程的执行范围已经完成,并且回调是从顶层系统启动的,就像新系统事件一样(例如点击事件处理程序)。

虽然父闭包仍然存在,因为setTimeout()中的匿名函数仍然可以引用这些变量,但是父作用域的实际执行已经完成,因此try / catch的范围已经完成。

setTimeout()匿名函数的执行上下文是顶级(由系统启动),因此没有父上下文可以放入try / catch。您可以在匿名中放置try / catch函数,但从那里抛出将返回到称为setTimeout()回调的系统。

要让您自己的代码捕获setTimeout()回调中发生的任何异常,您需要在回调中放置一个try / catch。

  setTimeout(function() {
    try {
        console.log("Throwing Error...");
        throw({message:"Ouch!"});
    } catch(e) {
        console.log(e.message);
    }
  }, 500);

如果你解释了你试图解决的真正问题(而不是这个制造的测试用例),我们可能会提供一些有用的选择。


编辑现在你已经展示了你真正试图解决的问题。 require.js库通过调用onError方法启动每个错误。 onError方法的默认实现是抛出异常的原因。您可以分配自己的onError处理程序并处理回调中的错误,而不是异常。这听起来是正确的方式。

来自requirejs来源:

/**
 * Any errors that require explicitly generates will be passed to this
 * function. Intercept/override it if you want custom error handling.
 * @param {Error} err the error object.
 */
req.onError = function (err) {
    throw err;
};

答案 1 :(得分:1)

throw阻止浏览器调用catch回调时,setTimeout发生了一段时间。

catch使用逻辑范围,而不是词法范围)

答案 2 :(得分:1)

前一位回答者正确解释了这一点。

另一种思考方式是它不工作,因为setTimeout完成正常,并且在最初运行时不会抛出异常。然后,当您不再位于try-catch块中时,它将在稍后执行。

如果将try catch放在setTimeout函数中,它将起作用:

  setTimeout(function() {
     try {
         console.log("Throwing Error...");
         throw({message:"Ouch!"});
     } catch(e) {
       console.log(e.message);
     }
      }, 500);

如果您仍有疑问,请与我联系。

答案 3 :(得分:1)

使用这样的包装函数。

// wrapper function
var tryable = function(closure, catchCallback) {
    closure(function(callback) {
        return function() {
            try {
                callback();
            } catch(e) {
                catchCallback(e);
            }
        };
    });
};


function throwException() {
    throw new Error("Hi");
}
tryable(function(catchable) {
    setTimeout(catchable(throwException), 1000);
}, function(e) {
    console.log("Error:)", e);
});