【问题标题】:Force a controlled rejection in promise.allSettled()在 promise.allSettled() 中强制进行受控拒绝
【发布时间】:2022-11-16 08:25:17
【问题描述】:

我试图以受控方式强制拒绝 promise.allSettled() 函数。 这个想法是通过 API 批量运行一系列 url,这个 API 不时为给定请求返回 500 错误,并且可以安全地重试。所以我想在 promise.allSettled() 上触发拒绝,我可以在其中收集失败的 url,然后在递归时重新运行。

批量请求功能

export async function batchRequest(poolLimit, array, iteratorFn, exception) {
  const promises = []
  const racers = new Set()

  for (const item of array) {
    const pro = Promise.resolve().then(() => iteratorFn(item, array))
    promises.push(pro)
    racers.add(pro)
    const clean = () => racers.delete(pro)
    pro.then(clean).catch(clean)

    if (racers.size >= poolLimit) await Promise.race(racers)
  }


  const results = await Promise.allSettled(promises)

  // Collect errors rejected by iteratorFn,
  const rejected = results
    .filter(({ status, reason }) => status === 'rejected' && reason.name === exception)
    .map(({ reason }) => reason.error)

  // Recurse the array of rejected urls
  if (rejected.length) {
    await batchRequest(poolLimit, rejected, iteratorFn, exception)
  }
}

在这里,我们正常运行承诺,但收集所有被拒绝的 url,我试图使用 exception 'timeout' 作为规则来确定它是否需要重新运行,因为它只是一个超时错误。

迭代函数

async function runRequest(url) {
  try {
    const { data } = await axios('https://exampleAPI.com')
    // Take the data and write it somewhere...
  
  } catch (error) {

    if (error.response.status === 500) {
      throw { name: 'timeout', url }
    }
  }
})

const urls = [...many urls]
await batchRequest(100, urls, runRequest, 'timeout')

我收到一条错误消息

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 "#<Object>".] { code: 'ERR_UNHANDLED_REJECTION' }

我如何强制对promise.allSettled() 进行受控拒绝?

更新------

我发现未处理的拒绝是在我开始 batchrequest 的时候

await batchRequest(100, urls, runRequest, 'timeout')

我需要在那里尝试捕获,但重点是使用 promise.allSettled() 来吸收错误而不是脱离 batchrequest

【问题讨论】:

  • 我收到一条错误消息,说我无法将其放入捕获物中“ 是什么确切的错误?因为you most definitely can throw in a catch
  • 我得到这个 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 并在它到达 catch 块时发生
  • 这并不是说你不能把它扔进一个陷阱里。它只是说有一个未处理的承诺拒绝。所以,找到它是哪一个并处理它。

标签: javascript node.js async-await promise


【解决方案1】:

在我看来,您没有处理 runRequest 或第一次调用 iteratorFn 抛出的异常。这就是导致“未处理的异常”错误的原因。

我建议通过调试器运行此代码并逐行执行,直到找到导致抛出该异常的行。

【讨论】:

  • 我虽然 promise.allSettled() 通过创建对象 { status: 'rejected', reason: Error: an error } developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… 自动做到这一点
  • 你在这种情况下的承诺并不是拒绝。他们有一个未处理的异常。我鼓励您通过调试器运行它。我不完全确定 for 循环中的代码也能做什么,因为它写得很晦涩。你的问题可能就在那里。但我 95% 确定你没有正确处理错误。
  • 你是对的,这是第一个电话,我不明白的是为什么我无法处理promise.allSettled()拒绝的问题
【解决方案2】:

只需手动处理每个承诺并收集错误和结果,并在所有承诺都解决后返回或抛出:

const errors = [];
const results = [];

Promise.all(
  promises.map(p => p.then(r => results.push(r)).catch(e => errors.push(e))
).then(() => {
  if (errors.length) throw errors;

  return results;
});

【讨论】:

  • 我没有收集结果,我正在写文件,所以承诺在成功时不会返回任何东西
  • 一个挑剔:Array.prototype.push 不是绑定方法,因此不能作为回调传递。替换例如errors.pusherrors.push.bind(errors)
  • @Code Spirit 这没有考虑到我想控制拒绝的事实
  • @Álvaro 是的,你可以无限地链接承诺。我刚刚使用了一个简单的示例,但您仍然可以将自己的逻辑添加到处理程序中。
  • @CodeSpirit 但promise.all() 会在请求失败时停止请求,即使失败我也想继续
猜你喜欢
  • 1970-01-01
  • 2023-04-05
  • 2020-07-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-02
相关资源
最近更新 更多