Promise的串行和并行


一、promise用法

js中的promise是一个异步编程的解决方案,语法层面上他是一个构造函数,名字为Promise()。

Promise的三种状态

Promise正如字面意思-承诺,“承诺将来会执行”约定的事情。我们首先需要了解Promise的三种状态:

  • pending: 初始状态,既不是成功,也不是失败状态。
  • fulfilled: 意味着操作成功完成。
  • rejected: 意味着操作失败。

Promise构造函数参数介绍

Promise构造函数接收一个函数作为参数,该函数的两个参数分别是resolve和reject。resolve和reject是两个函数,由JavaScript引擎提供,不用自己部署。

//resolve, reject名称不能修改
const promise = new Promise(function(resolve, reject) {
    // ...some code
    if ( /*异步操作成功,执行resolve方法,目的一般是将某些结果返回出去*/ ) {
        resolve(value);
    } else {
        /*异步操作失败,执行reject方法,目的一般也是将某些结果返回出去*/
        reject(error);
    }
});

Promise实例对象的then()方法

Promise 实例生成以后,可以用then方法分别指定resolved状态和rejected 状态的回调函数。也就是对返回的任务结果进行处理。then方法可以接受两个回调函数作为参数。其中,第二个函数是可选的,不一定要提供。

promise.then(resolved = function(value) {
        // success,对返回的结果value进行处理
    },
    rejected = function(error) {
        //failure,直接把错误类型报给用户
    });

Promise实例对象的catch()方法

一般来说,不要在then方法里面定义 Reject 状态的回调函数(即then的第二个参数),最好使用catch方法。

// bad
promise
  .then(function(data) {
    // success
  }, function(err) {
    // error
  });

// good
promise
  .then(function(data) { //cb
    // success
  })
  .catch(function(err) {
    // error
  });

Promise实例对象的catch()方法

finally方法用于指定不管前面Promise对象状态如何,都会执行的操作。

	promise .then(result => {···}) 
	.catch(error => {···}) 
	.finally(()=> {···})

上面代码中,不管promise最后的状态,在执行完then或catch指定的回调函数以后,都会执行finally方法指定的回调函数。
finally方法的回调函数不接受任何参数,它与Promise对象状态无关,不依赖于 Promise 的执行结果。

二、Promise.all

promise.all()该方法用于将多个Promise实例,包装成一个新的Promise实例。

传一个promise的数组,当所有的promise都完成(resolved),回调所有成功的结果, 如果有一个回调执行失败,then是不会执行的,则在catch回调第一个失败的结果
几个异步操作是强相关的,后续步骤必须依赖这几个步骤全部成功才能进行
promise.all将多个promise放在一起处理,能简化回调的处理(不然需要调很多次,不科学),一个then回调就能拿到所有数据,对其进行处理,也能用一个catch回调捕获所有的异常

var p = Promise.all([p1,p2,p3]);
  • 只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
  • 只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
  • 几个异步操作是强相关的,后续步骤必须依赖这几个步骤全部成功才能进行

示例–执行成功

代码如下(执行成功示例):

getPromise(a) {
  return new Promise((resolve, reject) => {
     if (a > 0) {
       console.log(a);
       resolve("execute in p" + a + ".then");
     } else {
       reject("error in p" + a, error);
     }
   })
 },
 testPromise(){
   console.log("test")
   const p1 = this.getPromise(1);
   const p2 = this.getPromise(2);
   const p3 = this.getPromise(3);


   const promiseArr = [p1,p2,p3];

   Promise.all(promiseArr).then((results) => {
     console.log('success:', results)
   }).catch(e => { // 失败的时候则返回最先被reject失败状态的值
     console.log("error", e)
   })

 }

只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。

在这里插入图片描述

示例–执行失败

代码如下(执行失败示例1):

getPromise(a) {
        return new Promise((resolve, reject) => {
          if (a > 0) {
            console.log(a);
            resolve("execute in p" + a + ".then");
          } else {
            reject("error in p" + a + ".error");
          }
        })
      },
      testPromise(){
        console.log("test")
        const p1 = this.getPromise(1);
        const p2 = this.getPromise(-2);
        const p3 = this.getPromise(3);

 
        const promiseArr = [p1,p2,p3];

        Promise.all(promiseArr).then((results) => {
          console.log('success:', results)
        }).catch((error) => { // 失败的时候则返回最先被reject失败状态的值
          console.log("error", error)
        })

      }

执行结果 : error error in p-2.error

代码如下(执行失败示例2):

getPromise(a) {
        return new Promise((resolve, reject) => {
          if (a > 0) {
            console.log(a);
            resolve("execute in p" + a + ".then");
          } else {
            reject("error in p" + a + ".error");
          }
        })
      },
      testPromise(){
        console.log("test")
        const p1 = this.getPromise(1);
        const p2 = this.getPromise(-2);
        const p3 = this.getPromise(-3);

 
        const promiseArr = [p1,p2,p3];

        Promise.all(promiseArr).then((results) => {
          console.log('success:', results)
        }).catch((error) => { // 失败的时候则返回最先被reject失败状态的值
          console.log("error", error)
        })

      }

执行结果 : error error in p-2.error

只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

总结

Promise.all()

  • Promise.all方法可以把多个promise实例包装成一个新的promise实例;Promise.all([promise1,promise2]):Promise—最终返回Promise实例;
  • 全部加载成功 则返回所有promise实例中resolve()回来带的参数,按数组中一一对应的顺序所集合的数组
  • 若任意有一个失败 ,立即决议失败,将失败的promise实例(reject()中参数)传递给我们;
  • 若Promise.all([ ])中,数组为空数组,则立即决议为成功执行resolve( );
  • 需要特别注意的是,Promise.all获得的成功结果的数组里面的数据顺序和Promise.all接收到的数组顺序是一致的,即p1的结果在前,即便p1的结果获取的比p2要晚。这带来了一个绝大的好处:在前端开发请求数据的过程中,偶尔会遇到发送多个请求并根据请求顺序获取和使用数据的场景,使用Promise.all毫无疑问可以解决这个问题。

三、Promise.all, reduce的区别

这里尝试了案例,但是自己的测试结果很迷惑,应该是测试的方式不对
以下案例是网上找的别的进行测试
案例参考来源

test_promise_Promise_all

// 辅助方法 makePromise 用来生成 Promise
makePromise(name, delay) {
  return new Promise((resolve) => {
    console.log(`${name} started`);
    setTimeout(() => {
      console.log(`${name} completed`);
      resolve(name);
    }, delay);
  });
},
test_promise_Promise_all(){
  const app = this;
  // 下面的 data 变量是演示用的数据,代表 setTimeout 的延时。
  const data = [2000, 1, 1000];
  Promise.all(data.map((v, k) => app.makePromise(k, v))).then(res => {
    console.log(res);
  });
},

执行结果
Promise.all 方法,会等所有 Promise 执行完毕后,把结果放在数组里,注意这里 Promise 的执行不存在什么顺序还是并发问题,因为 Promise 本身就代表一个已经执行的过程,所以 Promise.all 就是在等所有过程结束

0 started App.vue:46
1 started App.vue:46
2 started App.vue:46
1 completed App.vue:48
2 completed App.vue:48
0 completed App.vue:48
Array(3) [ 0, 1, 2 ]

test_promise_reduce

// 辅助方法 makePromise 用来生成 Promise
makePromise(name, delay) {
  return new Promise((resolve) => {
    console.log(`${name} started`);
    setTimeout(() => {
      console.log(`${name} completed`);
      resolve(name);
    }, delay);
  });
},
test_promise_reduce(){
	// 首先加入 bluebird 的 Promise 对象
  const Promise = require('bluebird'); // 这里的 bluebird 好像是一个第三方的库
  const app = this;
  // 下面的 data 变量是演示用的数据,代表 setTimeout 的延时。
  const data = [2000, 1, 1000];
  Promise.reduce(data,(total, v, k) => {
    return app.makePromise(k, v).then(res => {
      return total + res;
    });
  }, 0).then(res => {
    console.log(res);
  })
}

执行结果
Promise.reduce 方法是一个顺序执行 Promise 的方法,所谓顺序执行,其实就是从左到右按顺序去创建 Promise ,并且始终只有一个 Promise 在运行。看 bluebird 的 源码 ,可以发现,一些顺序执行的方法,比如 Promise.mapSeries 和 Promise.each ,都是基于 Promise.reduce 来实现的,这里的 reduce 和 Array.reduce 一样,测试代码:

0 started App.vue:46
0 completed App.vue:48
1 started App.vue:46
1 completed App.vue:48
2 started App.vue:46
2 completed App.vue:48
3

但是自己在测试的时候发现好像不太对啊??
以下为不完整测试,自己给自己绕晕了

test_promise_Promise_all

getPromise(a) {
   return new Promise((resolve, reject) => {
     if (a > 0) {
       let d = new Date()
       console.log(a + "start----" + d.getSeconds() + ":" + d.getMilliseconds());
       setTimeout(() => {
         console.log(a + "end----" + d.getSeconds() + ":" + d.getMilliseconds());
         resolve("execute in p" + a + ".then");
       }, a * 100)
     } else {
       reject("error in p" + a + ".error");
     }
   })
 },
 test_promise_Promise_all() {
   const p1 = this.getPromise(1);
   const p3 = this.getPromise(3);
   const p2 = this.getPromise(2);
   const p4 = this.getPromise(4);
   const p5 = this.getPromise(5);


   const promiseArr = [p1, p2, p3, p4, p5];

   Promise.all(promiseArr).then((results) => {
     console.log('success:', results)
   }).catch((error) => { // 失败的时候则返回最先被reject失败状态的值
     console.log('error:', error)
   })
 },
 }

执行结果
在这里插入图片描述
test_promise_reduce

getPromise(a) {
   return new Promise((resolve, reject) => {
     if (a > 0) {
       let d = new Date()
       console.log(a + "start----" + d.getSeconds() + ":" + d.getMilliseconds());
       setTimeout(() => {
         console.log(a + "end----" + d.getSeconds() + ":" + d.getMilliseconds());
         resolve("execute in p" + a + ".then");
       }, a * 100)
     } else {
       reject("error in p" + a + ".error");
     }
   })
 },
 test_promise_reduce() {
   const p1 = this.getPromise(1);
   const p3 = this.getPromise(3);
   const p2 = this.getPromise(2);
   const p4 = this.getPromise(4);
   const p5 = this.getPromise(5);


   const promiseArr = [p1, p2, p3, p4, p5];

   let doTask = promiseArr.reduce((prev, next) => prev.then(() => next), Promise.resolve());
   doTask.then(result => {
     console.log('success:', result)
   }).catch(error => {
     console.log("error", error)
   });
 }

执行结果

1start----42:660
3start----42:661
2start----42:661
4start----42:661
5start----42:661
1end----42:660
2end----42:661
3end----42:661
4end----42:661
5end----42:661
success: execute in p5.then

重新测试:好像和 newPromise 没关系,好像是 newPromise 的方式不对,new 的时候好像就执行了,所以上面测不出来

makePromise(a, delay) {
 return new Promise((resolve, reject) => {
    if (a >= 0) {
      let d = new Date()
      console.log(a + "start----" + d.getSeconds() + ":" + d.getMilliseconds());
      setTimeout(() => {
        console.log(a + "end----" + d.getSeconds() + ":" + d.getMilliseconds());
        resolve("execute in p" + a + ".then");
      }, delay)
    } else {
      reject("error in p" + a + ".error");
    }
  })
},
test_promise_Promise_all(){
  const app = this;
  const data = [2000, 1, 1000];
  Promise.all(data.map((v, k) => app.makePromise(k, v))).then(res => {
    console.log(res);
  });
},
test_promise_reduce(){
  const Promise = require('bluebird');
  const app = this;
  const data = [2000, 1, 1000];
  Promise.reduce(data,(total, v, k) => {
    return app.makePromise(k, v).then(res => {
      return total + res;
    });
  }, 0).then(res => {
    console.log(res);
  })
}

执行结果
在这里插入图片描述
在这里插入图片描述

总结

  • promise.all : 是并发执行
  • reduce : 是串行执行
    • reduce 是顺序执行的,从左到右按顺序去创建 Promise ,并且始终只有一个 Promise 在运行
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值