如何在 JavaScript 中延迟重试异步函数?

Ole*_*ann 2 javascript node.js promise async-await

我正在尝试从数据库中获取记录。由于竞争条件,当我第一次尝试获取记录时,记录可能甚至可能不存在。我如何将其包装在重试逻辑中而不发疯?我似乎太愚蠢了

  const booking = await strapi.query("api::booking.booking").findOne({
    where: {
      id: id,
    },
  });
Run Code Online (Sandbox Code Playgroud)

此代码应n延迟几t毫秒重试。谢谢并充满爱意。

我尝试过的:

async function tryFetchBooking(
  id,
  max_retries = 3,
  current_try = 0,
  promise
) {
  promise = promise || new Promise();

  // try doing the important thing
  const booking = await strapi.query("api::booking.booking").findOne({
    where: {
      id: id,
    },
  });

  if (!booking) {
    if (current_try < max_retries) {
      console.log("No booking. Retrying");
      setTimeout(function () {
        tryFetchBooking(id, max_retries, current_try + 1, promise);
      }, 500);
    } else {
      console.log("No booking. Giving up.");
      promise.reject(new Error("no booking found in time"));
    }
    promise.catch(() => {
      throw new Error(`Failed retrying 3 times`);
    });
  } else {
    console.log("Found booking with retry");
    promise.resolve(booking);
  }
}

const booking = await tryFetchBooking(id);
Run Code Online (Sandbox Code Playgroud)

抛出的错误:

This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason:
TypeError: Promise resolver undefined is not a function
Run Code Online (Sandbox Code Playgroud)

Ber*_*rgi 5

这种promise.reject()方法promise.resolve()是行不通的,你无法解决来自外部的承诺。而且你不应该需要 - 只需return/throw来自你的async函数!唯一需要构造 a 的地方new Promise是一个小辅助函数

function delay(t) {
  return new Promise(resolve => {
    setTimeout(resolve, t);
  });
}
Run Code Online (Sandbox Code Playgroud)

然后你可以以递归方式编写你的函数:

async function tryFetchBooking(
  id,
  max_retries = 3,
  current_try = 0,
) {
  let booking = await strapi.query("api::booking.booking").findOne({
    where: {
      id: id,
    },
  });

  if (!booking) {
    if (current_try < max_retries) {
      console.log("No booking. Retrying");
      await delay(500);
//    ^^^^^^^^^^^^^^^^
      booking = await tryFetchBooking(id, max_retries, current_try + 1);
//              ^^^^^^^^^^^^^^^^^^^^^
      console.log("Found booking with retry");
    } else {
      console.log("No booking. Giving up.");
      throw new Error("no booking found in time");
      // or if you prefer the other error message:
      throw new Error(`Failed retrying 3 times`);
    }
  }
  return booking;
}
Run Code Online (Sandbox Code Playgroud)

甚至以迭代的方式:

async function tryFetchBooking(id, maxRetries = 3) {
  let currentTry = 0;
  while (true) {
    const booking = await strapi.query("api::booking.booking").findOne({
      where: {
        id: id,
      },
    });

    if (booking) {
      return booking;
    }
    if (currentTry < maxRetries) {
      await delay(500);
      currentTry++;
    } else {
      console.log("No booking. Giving up.");
      throw new Error("no booking found in time");
    }
  }
}
Run Code Online (Sandbox Code Playgroud)