关于 【顺序执行Promise】 的一些理解

时间:2020-09-26 18:29:00 来源:互联网 热度: 作者: 佚名 字体:

前言

  近日工作上有一个需求,页面上有一个历史记录的东西,存储了最近使用的10张图片(大概知道下背景就好,不用深究)每一次页面刷新,ready后,要去服务器拉取那几张图片的URL,以便在页面上展示,因为产品要求历史记录的图片要按使用的时间顺序排列展示,我想了一下,决定按顺序发起【拉取图片URL】的请求(不要问我为什么)。在使用过程中碰到了问题,网友的答案我不大满意,所以特此总结一下。

套路

  处理这类问题的方法有以下两种:

  • Promise链式执行
  • 利用async/await

  我姑且认为大家的Promise是这么发出去的:

 1 /**
 2  * 不带参数
 3  */
 4 function p1() {
 5     // ... 前置处理
 6     return new Promise((resolve, reject) => {
 7         // ... 业务代码
 8 
 9     })
10 }
11 
12 p1().then(res => {
13     // 后续处理
14 }, err => {
15     // 后续处理
16 })
 1 /**
 2  * 带参数
 3  */
 4 function p1(param) {
 5     // ... 前置处理
 6     return new Promise((resolve, reject) => {
 7         // 业务代码
 8 
 9     })
10 }
11 
12 p1(param).then(res => {
13     // 后续处理
14 }, err => {
15     // 后续处理
16 })

  接下来我将分【带参数】和 【不带参数】两种情况,分别说明。

代码

不带参数

链式执行法

 1 function p1() {
 2     return new Promise((resolve, reject) => {
 3         resolve(1);
 4     })
 5 }
 6 
 7 function p2() {
 8     return new Promise((resolve, reject) => {
 9         resolve(2);
10     })
11 }
12 
13 function queue(...t) {
14     // 返回一个resolve状态的Promise对象,方便第一次在then中调用异步任务
15     let _queue = Promise.resolve();
16     let result = [];
17     t.forEach(p => {
18         _queue = _queue.then(p).then(res => {
19             result.push(res);
20             // 为了在最后一个then中获取到结果,因为then返回的是一个新的Promise实例
21             // 如果在外层有存储结果的对象,这里就不用return
22             return result;
23         });
24     });
25     return _queue;
26 }
27 
28 queue(p1, p2).then(res => {
29     console.log(res); // [1, 2]
30 })

async/await法

 1 function p1() {
 2     return new Promise((resolve, reject) => {
 3         resolve(1);
 4     }).then(() => {
 5         return "ok";
 6     })
 7 }
 8 
 9 function p2() {
10     return new Promise((resolve, reject) => {
11         resolve(2);
12     })
13 }
14 
15 async function exec() {
16     // ... 前置处理
17     let result = [];
18     console.log("执行p1")
19     let res1 = await p1();
20     console.log("执行p2");
21     let res2 = await p2();
22     // ... 若干promise
23     result.push(res1, res2);
24     return Promise.resolve(result);
25 }
26 
27 exec().then(res => {
28     console.log(res); // ["ok", 2]
29 });
30 
31 /**
32  * 注意:此处的代码并不会等exec()函数执行结束后才执行
33  * 因为在exec()中执行的Promise,一经发出会立即执行,then中的处理函数进入微任务队列,等宏任务执行完后,
34  * 再来执行微任务队列中的所有函数,如此反复。所以此处的代码在第一个Promise发出后,就会执行。
35  * 因为此文分享 [Promise顺序执行],所以不过多谈及这个,但还是提一下吧。36  */
37 console.log("乱入");

这样也可以:

 1 function p1() {
 2     return new Promise((resolve, reject) => {
 3         resolve(1);
 4     }).then(() => {
 5         return "ok";
 6     })
 7 }
 8 
 9 function p2() {
10     return new Promise((resolve, reject) => {
11         resolve(2);
12     })
13 }
14 
15 async function exec(...t) {
16     // ... 前置处理
17     let result = [];
18     for (let p of t) {
19         let res = await p();
20         result.push(res);
21     }
22     return Promise.resolve(result);
23 }
24 
25 exec(p1, p2).then(res => {
26     console.log(res); // ["ok", 2]
27 });

带参数

链式执行法

 1 function p1(id) {
 2     return new Promise((resolve, reject) => {
 3         resolve(id);
 4     })
 5 }
 6 
 7 function queue(ids) {
 8     // ... 前置处理
 9     let result = [];
10     let _queue = Promise.resolve();
11     ids.forEach(function(id) {
12         _queue = _queue.then(() => {
13             // 只有这样,后面那个then才可以获取到p1的执行结果
14             return p1(id);
15         }).then(res => {
16             result.push(res);
17             return result;
18         })
19     })
20     return _queue;
21 }
22 
23 queue([1, 2, 3]).then(res => {
24     console.log(res); // [1, 2, 3]
25 })

这样也可以:

 1 function p1(id) {
 2     return new Promise((resolve, reject) => {
 3         resolve(id);
 4     })
 5 }
 6 
 7 function queue(ids) {
 8     // ... 前置处理
 9     let result = [];
10     let _queue = Promise.resolve();
11     ids.forEach(function(id) {
12         _queue = _queue.then(() => p1(id).then(res => {
13             result.push(res);
14             return result;
15         }));
16     })
17     return _queue;
18 }
19 
20 queue([1, 2, 3]).then(res => {
21     console.log(res); // [1, 2, 3]
22 })

async/await法

 1 function p1(id) {
 2     return new Promise((resolve, reject) => {
 3         resolve(id);
 4     })
 5 }
 6 
 7 async function exec(...ids) {
 8     // ... 前置处理
 9     let result = [];
10     for (let id of ids) {
11         let res = await p1(id);
12         result.push(res);
13     }
14     return Promise.resolve(result);
15 }
16 
17 exec(1, 2).then(res => {
18     console.log(res); // [1, 2]
19 });