【问题标题】:Promise.all doesn't return none of it's promises if one of them fail [duplicate]如果其中一个失败,Promise.all 不会返回任何承诺 [重复]
【发布时间】:2018-09-07 08:35:45
【问题描述】:

我已经发布了question earlier about Promise.all 和 d3.js v5,但是关于这段代码的另一个问题出现了:

var files = ["data1.json", "data2.json", "data3.json"];
var promises = [];

files.forEach(function(url) {
    promises.push(d3.json(url))
});

Promise.all(promises).then(function(values) {
    console.log(values)
});

如果其中一个 URL 无效,Promise.all 不会返回任何结果;换句话说,所有响应都必须对 Promise.all 有效才能返回值。如果其中一个 URL 出错,如何获得其他响应?

【问题讨论】:

  • 您可以使用 Observable 来处理这个问题,因为它具有强大的功能,例如下一个、重试等……有了承诺,如果一个请求失败,代码执行就会停止。但是使用 Observable,如果一个请求失败,则可以完成另一个请求

标签: javascript promise es6-promise


【解决方案1】:

Promise.all 就是这样工作的。但是如果你想让它适用于被拒绝的承诺,你可以这样做:

var files = ["data1.json", "data2.json", "data3.json"];
var promises = [];

files.forEach(function(url) {
    promises.push(
      d3.json(url)
        .then(function(data) {
          return {success: true, data: data};
        }, function() {
          return {success: false};
        })
    )
});

Promise.all(promises).then(function(values) {
    console.log(values)
});

注意Promise#then可以接受两个函数作为参数,第一个在promise被解析时调用,第二个在promise被拒绝时调用。

您可以手动解决被拒绝的承诺,并且可以返回一个标识符以了解调用是成功还是失败,就像我使用 success 键所做的那样。

【讨论】:

  • 不需要Promise.resolve,直接返回对象即可。
  • “我不是 D3 的专家,但我认为 d3.json 返回一个有效的 promise 对象”...是的,确实如此!
【解决方案2】:

使用Promise.all,您需要确保每个 Promise 都能解决(意味着它不会拒绝)。很容易做到这一点,只需处理拒绝并从中恢复。例如:

var files = ["data1.json", "data2.json", "data3.json"];
var promises = files.map(function(url) {
  return d3.json(url)
    .catch(function (err) {
      return {
        error: err
      }
    })
});

Promise.all(promises).then(function(values) {
  console.log(values)
});

所以你只需要添加catch 块:

.catch(function (err) {
  return {
    error: err
  }
}

【讨论】:

    【解决方案3】:

    你想要像Promise.settle 这样的东西。您可以使用 Bluebird 和 .reflect(): http://bluebirdjs.com/docs/api/reflect.html

    function settle (promises) {
      return Promise.all(promises.map(promise => promise.reflect()));
    }
    
    
    var x = [Promise.resolve(1), Promise.reject(new Error("omg")), Promise.resolve(2)];
    
    settle(x).then(console.log)
    <script src="//cdn.jsdelivr.net/bluebird/3.5.0/bluebird.js"></script>

    【讨论】:

      【解决方案4】:

      尝试将每个 Promise 包装到您的自定义 Promise 中并解析它们。

      这里是例子:

      const wrappedPromises = promises.map(promise => {
        if (promise) {
          return new Promise((resolve, reject) => {
            promise.then(resolve).catch(resolve);
          });
        }
      });
      
      Promise.all(wrappedPromises).then(function(values) {
        console.log(values)
      });
      

      【讨论】:

        【解决方案5】:

        编写您自己的Promise.all 版本。跟踪已解决和已拒绝的承诺,并在所有承诺都已解决或被拒绝后返回您认为合适的任何数组。

        【讨论】:

          猜你喜欢
          • 2013-09-29
          • 2020-02-29
          • 2019-08-21
          • 1970-01-01
          • 1970-01-01
          • 2015-10-27
          • 2015-11-27
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多