Promise.all使用场景

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Promise.all使用场景相关的知识,希望对你有一定的参考价值。

参考技术A 问题描述:

Promise.all详情资料可查看: https://developer.mozilla.org/zh-CN/docs/Web/javascript/Reference/Global_Objects/Promise/all

如果参数中 promise 有一个(p2)失败(rejected),此实例回调失败(reject),就不再执行then方法回调,被catch掉了,打印了reject结果。

当然,也可以不使用Promise.all,但如果多个接口之间需要同步进行,后一个接口依赖前一个接口的返回值,这种情况做同步处理就麻烦一点了。

但是,使用Promise.all,如果有一个回调执行失败,即使其他几个promise已经进入resolved状态,then也不会执行的,或者可以说所有的promise都失败了(都不能正常取到响应结果)

下面是我的解决办法:

你如何避免使用 Promise.all 的 Promise 构造函数反模式

【中文标题】你如何避免使用 Promise.all 的 Promise 构造函数反模式【英文标题】:How do you avoid the promise constructor antipattern with Promise.all 【发布时间】:2015-11-19 18:24:10 【问题描述】:

在使用多个 Promise 和 Promise.all 时如何避免 Promise 构造函数反模式?

假设我有以下代码:

getFoo = function() 
    return new Promise(function(resolve, reject) 
        var promises = [];
        promises.push(new Promise(function(resolve, reject) => 
            getBar1().then(function(bar1) 
                processBar1(bar1); 
                resolve(bar1);
            );
        ));
        promises.push(new Promise(function(resolve, reject) => 
            getBar2().then(function(bar2) 
                processBar2(bar2); 
                resolve(bar2);
            );
        ));
        Promise.all(promises).spread(function(bar1, bar2) 
            var result = processBothBars(bar1, bar2);
            resolve(result);
        );
    );

它提出了反模式的一些基本问题,错误被吞噬,以及厄运金字塔。

顺便说一句,我正在使用蓝鸟。

【问题讨论】:

而不是顶部的return new Promise(..return Promise.all(...? @KevinB 但内部承诺仍会吞下错误 为什么需要内在的承诺?为什么不能将 getBar1() 的返回值推送到数组?我对 bluebird 不太熟悉,但是,如果它遵循原生 Promise 功能,那么上面的 sn-p 中根本不需要 new Promise 【参考方案1】:

Fwiw bluebird 在这方面证明了一些糖:

getFoo = function() 
     return Promise.join(getBar1().tap(processBar1),
                         getBar2().tap(processBar2),
                         processBothBars);

【讨论】:

数组在那里做什么? @Bergi 从我没有注意到需要 processBothBars 的时候就偷偷溜进来了,所以它是 .all【参考方案2】:

无需在此处创建您自己的任何 Promise,因为 getBar1()getBar2() 都已经返回 Promise - 至少我们假设是这样,因为两者都是 thenable。

提供processBar1processBar2分别返回你感兴趣的结果,代码会简化如下:

var getFoo = function() 
    // write promises as an array literal
    var promises = [
        getBar1().then(processBar1),//result returned by getBar1() is automatically passed to processBar1
        getBar2().then(processBar2) // ... ditto ...
    ];
    return Promise.all(promises).spread(processBothBars);
;

【讨论】:

我不明白apply 的作用。为什么不简化为.spread(processBothBars) @Bergi,我希望我能想到你的 .spread(processBothBars) 事情。我承认我的思想不是特别分散。【参考方案3】:

你可以一起摆脱new Promise

getFoo = function() 
    var promises = [];
    promises.push(getBar1().then(function(bar1) 
        processBar1(bar1);
        return bar1;
    ));
    promises.push(getBar2().then(function(bar2) 
        processBar2(bar2);
        return bar2;
    ));
    return Promise.all(promises).spread(function(bar1, bar2) 
        var result = processBothBars(bar1, bar2);
        return result;
    );

// start mock
function getBar1() 
    return Promise.resolve(name:'bar1',processed: false);

function getBar2() 
    return Promise.resolve(name:'bar2',processed: false);

function processBar1(bar1) 
  bar1.processed = true;

function processBar2(bar2) 
  bar2.processed = true;

function processBothBars (bar1, bar2) 
  return [bar1, bar2].filter(function (bar) 
    return bar.processed;
  ).map(function (bar) 
    return bar.name;
  );

Promise.prototype.spread = function (fn) 
  return this.then(function (arr) 
      return fn.apply(this, arr);
  );
;
// end mock

var getFoo = function (fail) 
    var promises = [];
    promises.push(getBar1().then(function (bar1) 
        processBar1(bar1);
        if (fail) 
          throw 'getBar1 Failed!';
        
        return bar1;
    ));
    promises.push(getBar2().then(function (bar2) 
        processBar2(bar2);
        return bar2;
    ));
    return Promise.all(promises).spread(function (bar1, bar2) 
        var result = processBothBars(bar1, bar2);
        return result;
    );

getFoo().then(function (result) 
    console.log(result); // ['bar1', 'bar2']
);
getFoo(true).then(function (result) 
    console.log(result); // doesn't happen
).catch(function (e) 
    console.error(e); // Error: getBar1 Failed!
);

.then 返回一个 Promise,因此无需创建一个新的包装它的 Promise,除非您想防止错误到达外部 Promise。

【讨论】:

您忘记了 2 个 thens 中的 returning 值 如果您不返回任何内容,您将返回undefined 来自getBar1() 的错误是否会传播到getFoo() 的结果? @Petah:是的 - 与问题中提供的代码相比 @Petah 添加了演示,带有(弱)模拟的 .spread,仅适用于具有原生 Promise 支持的浏览器。包括错误示例。

以上是关于Promise.all使用场景的主要内容,如果未能解决你的问题,请参考以下文章

vue promise.all使用

怎样同时获取10000+接口的返回值:Promise.all高并发限制解决方案

怎样同时获取10000+接口的返回值:Promise.all高并发限制解决方案

Promise.prototype.then()学习

Promise.all()使用方法

await 与 Promise.all 结合使用