捕获setInterval中的异常

nem*_*emo 8 javascript node.js

快速问题,如果我这样做:

setInterval(function() {
    try {
        riskyFunc();
    } catch(e){
        console.log(e);
    }
}, 1000);
Run Code Online (Sandbox Code Playgroud)

在我的脑海里,我想如果出现任何问题riskyFunc(),它就会被抓住.这是真的?我内心确实也有一些异步调用riskyFunc().

Eth*_*own 14

是的,它将被捕获:但仅在执行回调时.也就是说,如果riskyFunc抛出异常,则在一秒钟内执行回调之前,它不会被捕获到您的示例中.

您之前可能已经听说过在使用异步方法时必须小心异常,而人们通常会犯这样的错误:

try {
    setInterval(function() {
        riskyFunc();
    }, 1000);
} catch(e) {
    console.error(e);
}
Run Code Online (Sandbox Code Playgroud)

riskyFunc抛出异常时它们会混淆并且没有被捕获.它没有被捕获,因为你打电话时不会发生异常setInterval; 它发生setInterval在将来某个时候调用匿名函数时,它在原始try/catch块的上下文之外.您正在以正确的方式执行此操作:通过在回调内执行异常处理.

如果riskyFunc反过来调用异步调用,那些也必须以这种方式处理异常.例如:

function riskyFunc() {
    // do some stuff
    asyncFn(function(){
        throw new Error('argh');
    }
}
Run Code Online (Sandbox Code Playgroud)

在您的setInterval调用中的try/catch块中不会捕获该异常.您必须继续应用该模式:

function riskyFunc() {
    // do some stuff
    asyncFn(function() {
        try {
            // work that may throw exception
        } catch(e) {
            console.error(e);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您希望异常"向上传播",则必须使用promises或其他方式来指示成功/失败.这是一种常见的方法,通过使用能够报告错误的"完成"回调:

function riskyFunc(done) {
    // do some stuff
    asyncFn(function() {
        try {
            // do some more risky work
            done(null, 'all done!');
        } catch(e) {
            done(e);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以在你的电话中调用它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);
    }
}
Run Code Online (Sandbox Code Playgroud)