Pesquisa de site

node.js - Timeout em async/await


Estou com Node.js e TypeScript e estou usando async/await. Este é o meu caso de teste:

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

Eu gostaria de definir um tempo limite para a função como um todo. Ou seja, se res1 leva 2 segundos, res2 leva 0,5 segundos, res3 leva 5 segundos, eu gostaria de ter um tempo limite que, após 3 segundos, me permitisse lançar um erro.

Com uma chamada normal de setTimeout é um problema porque o escopo é perdido:

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';
}

E eu não consigo capturá-lo com o Promise.catch normal:

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

Alguma ideia de como resolver?

Resposta #1

Você pode usar Promise.race para criar um tempo limite:

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
})

Você não pode usar setTimeout sem envolvê-lo em uma promise.

Resposta #2

Ok, eu encontrei este caminho:

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;
    });

}

Alguém cometeu erros?

As coisas que me deixam um pouco desconfiado é que usar Promises como estratégia de assincronidade nos levará a alocar muitos objetos que alguma outra estratégia precisaria, mas isso é fora do tópico.

Artigos relacionados