【问题标题】:Is there a way to return all successful promises from fetch until one fails?有没有办法从 fetch 返回所有成功的承诺,直到失败?
【发布时间】:2022-01-24 15:10:30
【问题描述】:

Javascript 函数 Promise.allSettled 等待所有已解决或已拒绝的 Promise 完成。如果其中任何一个被拒绝,Promise.all 将不会返回已解决的承诺,并且 Promise.racePromise.any 只给出第一个已解决或已实现的承诺。

有没有办法发送多个承诺(比如 100 个),然后一旦一个失败(可能有 20 个成功)取消未解决的承诺(其中有 100 - 20 - 1 = 79 个尚未解决) ?我什至不需要失败的细节,只需要一种 Promise.someSettled 函数。

对于上下文,我正在数据和 fetch 调用之间进行映射,我想知道需要重试哪些 fetch。

这可能吗?

【问题讨论】:

  • 听起来您正在尝试为大量异步调用构建进度指示器;最好在您的问题中提及这一点。
  • Promise 没有被取消的机制。除此之外,你想在这里建造什么? Promise 可能不适合你。
  • 如果没有一个 promise 失败会发生什么?
  • 可能只有我一个人,但“甚至不需要失败的详细信息”和“知道需要重试哪些获取”这两个陈述似乎相互矛盾。
  • 如果目标是重试失败的提取,那么您只需将重试模式分别应用于每个提取。在两行之间阅读,这就是您想要的,但还有一个额外的要求,即当一些任意数量的提取(或它们的重试)成功时重试停止。

标签: javascript promise


【解决方案1】:

因为输入承诺和输出解析值不是一对一的,我认为最简单的管理方法是在解析时推送到外部数组,并使用Promise.all 等待一个拒绝,例如:

const makePromises = () => Array.from(
  { length: 100 },
  (_, i) => new Promise((resolve, reject) => {
    setTimeout(() => {
      if (Math.random() > 0.05) resolve(i);
      else reject();
    }, 1000 * Math.random());
  })
);

const resolveValues = [];
Promise.all(
  makePromises()
    .map(prom => prom.then(val => {
      resolveValues.push(val);
    }))
)
  .then(() => {
    console.log('Unexpected - All promises resolved');
  })
  .catch(() => {
    const innerResolveValues = [...resolveValues];
    console.log('Done:');
    console.log(innerResolveValues);
  });

【讨论】:

  • 映射和推送真的很聪明。
【解决方案2】:

听起来您正在尝试为大量调用构建进度指示器。

一个简单的解决方案是将大量呼叫分成更小的组,并使用Promise.allSettled() 来确定每个组何时结束。然后,您可以将已完成的组数与未完成的组数进行比较,以衡量进度。

【讨论】:

  • 这肯定是一个很好的解决办法。
【解决方案3】:

是的,@Certainperformance 击中了它的头!这是组合 promise 数组的另一种方法,但想法完全相同:

for (var acc=[], pr=[], i=0; i<100; i++)
  pr.push(new Promise((rs,rj)=>setTimeout((i<20?rs:rj).bind(null,i),200*i))
    .then(d=>{acc.push(d)}))
Promise.all(pr).then(
 d=>{console.log("all done!", acc)},
 e=>{console.log("with some errors:", acc)} );
.as-console-wrapper {max-height: 100% !important; top: 0; }

在我的示例中,我让第一个完成承诺成功并拒绝后面的承诺(对于i&gt;=20)。这些承诺一个接一个地以 0.2 秒的顺序完成。因此,在 4.2 秒后,第一个被拒绝的 Promise 被返回,外部 .then() 的“失败”分支将被执行,在 acc 中列出累积的成功 Promise。

【讨论】:

    【解决方案4】:

    让我们添加一个生成器;)

    这样我们就不必等待所有的 Promise 解决或抛出一个 Promise 才能处理成功的项目。

    const makePromises = () => Array.from({
        length: 100
      },
      (_, i) => new Promise((resolve, reject) => {
        setTimeout(Math.random() > 0.05 ? resolve : reject, 1000 * Math.random(), i);
      })
    );
    
    // Takes anything iterable as long as it's syncronously iterable 
    // and a finite list.
    async function* asTheyResolve(promises) {
      let itemsLeft = 0,
        deferred;
    
      const init = (resolve, reject) => (deferred = { resolve, reject });
      // shove my result into the promise that is currently awaited
      const resolve = (value) => deferred.resolve(value);
      const reject = (error) => deferred.reject(error);
    
      for (let item of promises) {
        itemsLeft++;
        Promise.resolve(item).then(resolve, reject);
      }
    
      while (itemsLeft-- > 0) {
        // creates a new Promise and awaits it.
        yield await new Promise(init);
      }
    }
    
    
    (async () => {
      try {
        const start = performance.now();
        for await (let value of asTheyResolve(makePromises())) {
          console.log("time: %f value: %o", performance.now() - start, value);
        }
      } catch (error) {
        console.log("one has thrown", error);
      }
    })();

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-28
      相关资源
      最近更新 更多