在 Nodejs 中等待并重试

在其他编程语言(例如 Java、Ruby 和 Python)中,有 Thread.sleep()sleeptime.sleep() 方法来暂停当前线程的执行,并在指定时间后等待继续执行,当与循环一起使用时,它可以帮助解决竞争条件问题等。在 node.js 和一般的 JavaScript 中,由于单线程、事件驱动和异步架构的性质,暂停和等待的方式可能看起来不是很明显,也不常见。但是,由于在某些情况下仍然需要并且有助于使用 waitretry,因此可以在 nodejs 或 JavaScript 中模拟类似的功能和效果。

How to simulate sleep/wait with setTimeout

  • with new Promise
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
  • with util.promisify
import util from 'node:util';

const wait = util.promisify(setTimeout);

How to implement retry with back-off

  • with recursive functions
const retry = async (fn, depth = 0, numRetries = 3) => {
  try {
    return await fn();
  } catch (e) {
    if (depth === numRetries) {
      throw e;
    }
    console.log('retry...');
    await wait(2 ** depth * 10);
  
    return retry(fn, depth + 1, numRetries);
  }
}
  • with for loops
const retry = async (fn, retryDelayMs = 100, numRetries = 3) => {
  for (let attempt = 0; attempt <= numRetries; attempt++) {
    try {
      return await fn();
    } catch (e) {
      if (attempt === numRetries) {
        throw e;
      }
      console.log('retry...');
      await wait(retryDelayMs);

      retryDelayMs *= 2;
    }
  }
}
  • until function returns truthy value
const retry = async (fn, retryDelayMs = 100, numRetries = 3) => {
  let result;
  for(let i = 0; i < numRetries; i++) {
    try {
      result = await fn();
    } catch (e) {
      // ignore errors
    }
    if(result) {
      return result;
    }
    console.log('retry...');
    await wait(retryDelayMs);

    retryDelayMs *= 2;
  }
  return result;
};

参考资料

nodejs