Javascript 捕获setInterval中的异常
快速提问,如果我这样做:Javascript 捕获setInterval中的异常,javascript,node.js,Javascript,Node.js,快速提问,如果我这样做: setInterval(function() { try { riskyFunc(); } catch(e){ console.log(e); } }, 1000); 在我的脑海中,我在想,如果在riskyFunc()中出现任何错误,它就会被捕获。这是真的吗?我知道在riskyFunc()中肯定有一些异步调用。是的,它会被捕获:但只有在执行回调时才会被捕获。也就是说,如果riskyFunc抛出异常,则在一秒钟内执
setInterval(function() {
try {
riskyFunc();
} catch(e){
console.log(e);
}
}, 1000);
在我的脑海中,我在想,如果在
riskyFunc()
中出现任何错误,它就会被捕获。这是真的吗?我知道在riskyFunc()
中肯定有一些异步调用。是的,它会被捕获:但只有在执行回调时才会被捕获。也就是说,如果riskyFunc
抛出异常,则在一秒钟内执行回调之前,不会在示例中捕获该异常
您可能听说过,在使用异步方法时必须小心异常,人们通常犯的错误是:
try {
setInterval(function() {
riskyFunc();
}, 1000);
} catch(e) {
console.error(e);
}
当riskyFunc
抛出异常而未捕获时,他们会感到困惑。它不会被捕获,因为调用setInterval
时不会发生异常;当setInterval
在将来某个时候调用匿名函数时会发生这种情况,该函数不在原始try/catch块的上下文中。您使用的方法是正确的:在回调中执行异常处理
如果riskyFunc
反过来调用异步调用,那么这些调用也必须以这种方式处理异常。例如:
function riskyFunc() {
// do some stuff
asyncFn(function(){
throw new Error('argh');
}
}
该异常不会在setInterval
调用内的try/catch块中被捕获。您必须在以下位置继续应用图案:
function riskyFunc() {
// do some stuff
asyncFn(function() {
try {
// work that may throw exception
} catch(e) {
console.error(e);
}
}
}
如果希望异常“向上传播”,则必须使用承诺或其他方式来表示成功/失败。下面是一个常用方法,通过使用能够报告错误的“完成”回调:
function riskyFunc(done) {
// do some stuff
asyncFn(function() {
try {
// do some more risky work
done(null, 'all done!');
} catch(e) {
done(e);
}
}
}
然后,您可以在setTimeout
中调用它,并考虑可能的异步故障:
setTimeout(function() {
try {
riskyFunc(function(err, msg) {
// this will cover any asynchronous errors generated by
// riskyFunc
if(err) return console.error(err);
console.log(msg);
});
} catch(e) {
// riskyFunc threw an exception (not something it
// invoked asynchronously)
console.error(e);
}
}
如果riskyFunc是
function() {
process.nextTick(function() {
throw "mistake";
});
}
你的挡块抓不住。我相信这正是您所担心的情况,您所能做的就是设置全局异常处理程序,或者期待最好的结果。(不,承诺不会捕捉到这一点。它们不是魔法。)
setInterval
已经将块放入异步块中。并且异常不能在不同步的情况下被捕获。正确的模式是使用Promise对象,并在出现问题时调用fail()
操作。对于本例,我使用jQuery的Deferred
对象,但任何promise库都有类似的用法:
var promise = $.Deferred();
setInterval(function () {
try{
riskyFunc();
} catch (e) {
promise.reject(e);
}
promise.resolve(/* some data */);
}, 1000);
promise
.done(function (data) { /* Handled resolve data */ })
.fail(function (error) { /* Handle error */ });
请注意,由于您使用的是
setInterval
而不是setTimeout
,因此除非清除超时,否则将每秒调用一次,因此如果需要并行多次调用函数,您可能需要一系列承诺。感谢@Ethan Brown的详细解释。我认为您的上一次设置超时缺少计时器-请参见下文
setTimeout(function() {
try {
riskyFunc(function(err, msg) {
// this will cover any asynchronous errors generated by
// riskyFunc
if(err) return console.error(err);
console.log(msg);
});
} catch(e) {
// riskyFunc threw an exception (not something it
// invoked asynchronously)
console.error(e);
}
}, 1000)
如果您觉得这很有用,请您解释一下异常不能在不同步中捕获的含义。