ウェブサイト検索

node.js - async/await におけるタイムアウト


私は Node.js と TypeScript を使っており、async/await を使用しています。これが私のテストケースです:

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

全体の関数にタイムアウトを設定したいです。つまり、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';
}

そして、通常の Promise.catch ではそれをキャッチできません:

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

解決する方法について何かアイデアはありますか?

回答 #1

タイムアウトを作るために、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
})

あなたは setTimeout をプロミスでラップせずに使用することはできません。

回答 #2

わかった、私はこの方法を見つけた:

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

}

誰か間違えましたか?

私にとって少し気になるのは、非同期戦略としてPromiseを使用すると、他の戦略が必要とするよりも多くのオブジェクトを割り当てることになるという点ですが、これは本題から逸れています。

関連記事