异步/等待超时

nki*_*int 21 timeout node.js promise async-await typescript

我使用的是Node.js和TypeScript,我正在使用它async/await.这是我的测试用例:

async function doSomethingInSeries() {
    const res1 = await callApi();
    const res2 = await persistInDB(res1);
    const res3 = await doHeavyComputation(res1);
    return 'simle';
}
Run Code Online (Sandbox Code Playgroud)

我想为整个功能设置超时.即如果res1需要2秒,res2需要0.5秒,res3需要5秒我想要超时,3秒后让我抛出错误.

正常setTimeout调用是一个问题,因为范围丢失:

async function doSomethingInSeries() {
    const timerId = setTimeout(function() {
        throw new Error('timeout');
    });

    const res1 = await callApi();
    const res2 = await persistInDB(res1);
    const res3 = await doHeavyComputation(res1);

    clearTimeout(timerId);

    return 'simle';
}
Run Code Online (Sandbox Code Playgroud)

我无法正常地抓住它Promise.catch:

doSomethingInSeries().catch(function(err) {
    // errors in res1, res2, res3 will be catched here
    // but the setTimeout thing is not!!
});
Run Code Online (Sandbox Code Playgroud)

关于如何解决的任何想法?

Ber*_*rgi 36

您可以使用Promise.race超时:

Promise.race([
    doSomethingInSeries(),
    new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), 11.5e3))
]).catch(function(err) {
    // errors in res1, res2, res3 and the timeout will be caught here
})
Run Code Online (Sandbox Code Playgroud)

如果setTimeout不将其包含在承诺中,则无法使用.

  • @nkint:你不能停止承诺——它只代表一个结果(免责声明:除非你使用支持取消的承诺实现)。因此,如果您需要对正在进行的事情做任何事情,您需要手动完成(就像您在下面的答案中使用“clearTimeout”所做的那样)。 (2认同)

nki*_*int 5

好的,我找到了这种方式:

async function _doSomethingInSeries() {
    const res1 = await callApi();
    const res2 = await persistInDB(res1);
    const res3 = await doHeavyComputation(res1);
    return 'simle';
}

async function doSomethingInSeries(): Promise<any> {
  let timeoutId;

  const delay = new Promise(function(resolve, reject){
    timeoutId = setTimeout(function(){
      reject(new Error('timeout'));
    }, 1000);
  });

  // overall timeout
  return Promise.race([delay, _doSomethingInSeries()])
    .then( (res) => {
      clearTimeout(timeoutId);
      return res;
    });

}
Run Code Online (Sandbox Code Playgroud)

任何人的错误?

对我来说有点味道的事情是,使用 Promises 作为异步策略会让我们分配太多其他策略需要的对象,但这是题外话。