0

当使用 async await 时,有时我们希望将 Promise 保存在一个变量中,做一些其他的事情,然后再等待它。如果“其他东西”不需要很长时间,这可以正常工作:

try {
  const pWillReject = rejectAfter(8000);
  const someValue = await shortRunning();
  doSomethingWith(someValue);
  await pWillReject;
} catch (ex) {
  // handle the error
  console.log('caught', ex);
}
// continue

错误按预期被catch捕获,代码执行可以继续

但是,如果“其他事情”花费的时间太长,我们可能会收到“未处理的承诺拒绝”通知。代码执行被中断,catch 没有被执行。发生这种情况是因为,尽管我们最终附加了一个处理程序,但直到错误事件已经触发之后才完成。

try {
  const pWillReject = rejectAfter(8000);
  const someValue = await longRunning();
  doSomethingWith(someValue);
  // we never get here
  await pWillReject;
} catch (ex) {
  //catch is not executed
  console.log('caught', ex);
}
// no oppurtunity to continue

我不想为 UnhandledPromiseRejection 添加全局处理程序,因为在大多数情况下,我希望程序在这种情况下终止(因为它表示编码错误)。但是在这种情况下,在处理拒绝情况下(只是不够快),程序应该继续。

这个问题有什么好的解决方法?

我能想到的最好的方法是以非侵入性方式附加一个无操作处理程序,即

  const pWillReject = rejectAfter(8000);
  pWillReject.catch(ex=>{}); // do nothing, errors will be handled later

但我不喜欢这个

  1. 它使代码嘈杂
  2. 它不是自我记录 - 需要评论
  3. 最重要的是 - 它可能会错过真正的编码错误。如果承诺从未被等待,它可能会默默地失败。

有更好的选择吗?

完整代码示例:

async function go() {
  try {
    const pWillReject = rejectAfter(8000);
    const someValue = await shortRunning();
    doSomethingWith(someValue);
    await pWillReject;
  } catch (ex) {
    console.log('caught', ex);
  }
  console.log('success');
  try {
    const pWillReject = rejectAfter(8000);
    const someValue = await longRunning();
    doSomethingWith(someValue);
    await pWillReject;
  } catch (ex) {
    console.log('caught', ex);
  }
  console.log('failure');
}

go().catch(ex=> {
  console.log('global catch');
})

async function delay(ms) {
  return new Promise((r,x)=> {
    setTimeout(r, ms);
  });
}
async function rejectAfter(ms) {
  return new Promise((r,x)=> {
    setTimeout(x, ms, new Error("whatever"));
  });
}

function shortRunning() {
  return delay(1000);
}

function longRunning() {
  return delay(10000);
}

function doSomethingWith(obj) {
  console.info(obj);
}

注意在我的情况下,我使用的是节点,但是我认为这个问题同样适用于浏览器。

4

0 回答 0