【问题标题】:Promise.all.then is executed before the individual promises are completedPromise.all.then 在各个 Promise 完成之前执行
【发布时间】:2018-09-28 02:13:20
【问题描述】:

下面的示例代码代表了我正在尝试做的事情,并且对于为什么 Promises.all.then() 中的 console.log 甚至在单个承诺完成之前就完成了,我感到很困惑。我认为map 声明与它有关,可能是,但我不确定。

我使用map 的目的是收集所有成功和/或失败,并在稍后通知用户批量操作。

var requests = []; var success=[]; var failures = [];

requests.push(new Promise((resolve, reject) => setTimeout(() => resolve("foo success"), 2000)));
requests.push(new Promise((resolve, reject) => setTimeout(() => reject("bar failure"), 1000)));
requests.push(new Promise((resolve, reject) => setTimeout(() => resolve("foo2 success"), 2000)));
requests.push(new Promise((resolve, reject) => setTimeout(() => reject("bar2 failure"), 1000)));

Promise.all(requests.map(p => {
    p.then(r => {
        console.log(r)
        success.push(r);
    });
    p.catch((e) => { console.log(e); failures.push(e); });
})).then(function () { console.log("ALL promises completed")})

我可以知道上面的代码有什么问题吗?我没有按预期执行承诺吗?

【问题讨论】:

  • 我有一个类似问题的答案,尽管问题的表述不同:“如何满足 lint 规则'array-callback-return'?”:stackoverflow.com/a/45418236/2430549
  • 这里是关于代码风格的附加题外评论。 setTimeout 接受任何附加参数并将它们应用于回调。你也可以这样写,我认为这样更好看。 new Promise(resolve => setTimeout(resolve, 2000, "foo success"))

标签: javascript


【解决方案1】:

这是因为您的 requests.map(...) 回调没有返回任何内容,因此您将 Promises 映射到 undefined 值。因此,您正在等待带有 Promise.all 调用的 undefined 值数组。更改为以下内容:

Promise.all(requests.map(p => {
    p.then(r => {
      console.log(r)
      console.log("POSTed a record successfuly");
      success.push(r);
    });
    p.catch((e) => { console.log(e); failures.push(e); });
    return p;
})).then(function () { console.log("POSTED ALL")})

更新

正如@JoeFrambach 指出的那样,如果您希望Promise.all 包含原始requests Promises 的内容,您需要返回原始Promises。由于这很可能是您想要做的,我已经更新了我的答案。

【讨论】:

  • 啊,我真傻,非常感谢!!! (所以说我可以在接下来的 5 分钟内接受这个作为答案)
  • 这个答案实际上改变了您问题中代码的行为。您的地图可以为每个承诺添加额外的功能,但您应该返回原始承诺,而不是您的增强承诺。 .then 接受一个参数,即前一个承诺的解析值。这个答案总是返回 undefined 并丢弃响应。
  • 哦,我明白你的意思了,对了,我把原图还给我。。我用map只是为了收集失败和成功,稍后作为通知发送。。会修改
  • 是的,你可以把最后一行改成})).then(function (allResponses) { console.log("POSTED ALL", allResponses)})`
  • 是的,如果您的意图是让 Promise.all 的结果包含结果,则需要返回原始 Promises。更新。但请记住,您可能会在成功/失败消息之前看到"POSTED ALL"
【解决方案2】:

只需从您的地图回调函数中返回承诺

var requests = []; var success=[]; var failures = [];

requests.push(new Promise((resolve, reject) => setTimeout(() => resolve("foo success"), 2000)));
requests.push(new Promise((resolve, reject) => setTimeout(() => reject("bar failure"), 1000)));
requests.push(new Promise((resolve, reject) => setTimeout(() => resolve("foo2 success"), 2000)));
requests.push(new Promise((resolve, reject) => setTimeout(() => reject("bar2 failure"), 1000)));

Promise.all(requests.map(p => {
    p.then(r => {
        console.log(r)
        success.push(r);
    });
    p.catch((e) => { console.log(e); failures.push(e); });
    return p; // ADD THIS LINE
})).then(function () { console.log("ALL promises completed")})
   .catch(function() {console.log("FAILED PROMISE ALL")});

【讨论】:

  • 这会起作用,但请记住p.then 不会“改变” Promise,p.catch 也不会。因此,在等待返回的 p 时,您不会同时等待 thencatch 回调,而是等待 Promise before。有时这就是你想要的,但通常你想要返回 .then.catch 返回的 new 承诺。
【解决方案3】:

您需要在 .map 函数中返回一个承诺。 在 .map 函数中,将最后一行作为 return p。

Promise 都需要一系列的 Promise。您正在从 map 函数返回未定义的数组,因此它会立即得到解决。

【讨论】:

    猜你喜欢
    • 2019-02-22
    • 2019-03-07
    • 2018-04-05
    • 1970-01-01
    • 2021-03-28
    • 1970-01-01
    • 2016-10-07
    • 1970-01-01
    • 2016-05-13
    相关资源
    最近更新 更多