在下面的代码中,我故意抛出一个错误,但在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);
}
})();
答案 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);
});