如何在try代码块内函数中的setInterval中抛出错误并被外层catch捕获?为何同步回调错误可捕获而setInterval内不行?
异步回调错误捕获的问题解析
首先来解答你第二个问题:为什么noWait()的回调抛出的错误能被外层catch捕获,而waitForTimer()的不行?
- 对于
noWait()来说,它是同步执行的函数:当你调用noWait(()=>{ throw "this is error!!" })时,回调函数会立刻在当前的调用栈中执行——这个调用栈就在try代码块的范围内,所以抛出的错误会被同层级的catch直接捕获。 - 而
waitForTimer()里用到了setInterval,这是一个异步API:它的回调函数会被放到事件队列中,等到当前调用栈(也就是整个try块里的同步代码)执行完毕、调用栈清空后,才会被取出执行。这时候原来的try/catch所在的上下文已经不存在了,所以回调里抛出的错误找不到对应的catch,就会变成未捕获的全局错误。
接下来解决第一个问题:如何让setInterval内部的错误被外层catch捕获?
核心思路是把异步操作包装成Promise,然后用async/await来等待异步完成,这样异步操作中抛出的错误就能被try/catch捕获了。这里我们可以修改waitForTimer的实现:
async function why(){ try { function noWait(callback) { callback(); } // 修改为返回Promise的函数 function waitForTimer() { return new Promise((resolve, reject) => { var timer = setInterval(()=>{ clearInterval(timer); // 捕获回调内的错误并通过reject传递 try { throw "this is error??"; // 正常逻辑执行resolve() // resolve(); } catch (err) { reject(err); } }, 10); }); } // 用await等待异步操作,错误会被外层catch捕获 await waitForTimer(); noWait(()=>{ throw "this is error!!" }); } catch (err) { console.log(err); } } why()
如果你想保留回调的形式,也可以把回调执行逻辑包裹在Promise中:
async function why(){ try { function noWait(callback) { callback(); } async function waitForTimer(callback) { return new Promise((resolve, reject) => { var timer = setInterval(()=>{ clearInterval(timer); try { callback(); resolve(); } catch (err) { reject(err); } }, 10); }); } await waitForTimer(()=>{ throw "this is error??" }); noWait(()=>{ throw "this is error!!" }); } catch (err) { console.log(err); } } why()
这样修改后,setInterval回调里的错误会被内部try/catch捕获,再通过reject传递出去,最后由外层的await触发try/catch逻辑,实现错误的捕获。
内容的提问来源于stack exchange,提问作者YulePale
相关产品推荐
相关产品推荐

