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

  • A+
所属分类:Web前端
摘要

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


前言

  近日工作上有一个需求,页面上有一个历史记录的东西,存储了最近使用的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 });