Promise.all() 实现并发同步接收返回值
在日常项目应用中你是否碰到过这种情况:在加载某一个模块数据的时候,出于性能考虑(或某些不知名原因),后端给过来的接口有好几个,而我们需要都执行一遍才能得到我们想要的数据(散装接口)。这时候,如果几个接口数据比较小还好,我们可以一路 await 下去,或者用then嵌套,但是如果数据比较多,那等待时间可能就有点长了,对于界面渲染就不太友好了(可能卡一个地方好几秒)。那么这时候有办法在他们异步发送请求的同时,能在某一个地方获取到他们的数据,这不就节省了我大量时间么(这不正是我早上赶时间想要的效果么,边上厕所边刷牙(狗头)...,3分钟出门)Promise.all() 就能做到这一点。
介绍(来自于MDN):
Promise.all() 方法接收一个promise的iterable类型(注:Array,Map,Set都属于ES6的iterable类型)的输入,并且只返回一个Promise实例, 那个输入的所有promise的resolve回调的结果是一个数组。这个Promise的resolve回调执行是在所有输入的promise的resolve回调都结束,或者输入的iterable里没有promise了的时候。它的reject回调执行是,只要任何一个输入的promise的reject回调执行或者输入不合法的promise就会立即抛出错误,并且reject的是第一个抛出的错误信息。
MDN网站的demo
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3]).then((values) => {
console.log(values);
});
// expected output: Array [3, 42, "foo"]
自己些了个小例子测试了一下 看时间上到底有没有提升
普通接口调用写法 或者 使用es6的 async/await 异步转同步
// function Index() {
// 普通调用嵌套写法
// console.time()
// const p1 = new Promise((resolve, reject) => {
// console.log('这里是p1')
// setTimeout(() => {
// resolve('这里是p1的返回')
// }, 1000)
// }).then((r1) => {
// new Promise((resolve, reject) => {
// console.log('这里是p2')
// setTimeout(() => {
// resolve('这里是p2的返回')
// }, 1000)
// }).then((r2) => {
// console.log(r1)
// console.log(r2)
// console.timeEnd()
// })
// })
// }
//异步转同步
async function Index2() {
console.time()
const p1 =await new Promise((resolve, reject) => {
console.log('这里是p1')
setTimeout(() => {
resolve('这里是p1的返回')
}, 1000)
})
const p2 =await new Promise((resolve, reject) => {
console.log('这里是p2')
setTimeout(() => {
resolve('这里是p2的返回')
}, 1000)
})
console.log(p1)
console.log(p2)
console.timeEnd()
}
//Index();
Index2();
打印结果,差不多2s, 一步一步执行下来
使用Promise.all()来实现调用
async function Index() {
console.time()
const p1 = new Promise((resolve, reject) => {
console.log('这里是p1')
setTimeout(() => {
resolve('这里是p1的返回')
}, 1000)
})
const p2 = new Promise((resolve, reject) => {
console.log('这里是p2')
setTimeout(() => {
resolve('这里是p2的返回')
}, 1000)
})
Promise.all([p1, p2]).then((val) => {
console.log(val)
console.timeEnd()
})
//当然也可以使用 async/await写法
/*
const p = await Promise.all([p1, p2])
console.log(p);
console.timeEnd();
*/
//补充说明:如果我们的接口已经套上了一层 promise 便已经实现了同时执行异步的条件
//下面这种写法耗时和Promise.all也是一样的,但是嵌套多了可能代码就不太优雅了
/* p1.then((r1) => {
p2.then((r2) => {
console.log(r1)
console.log(r2)
console.timeEnd()
})
}) */
}
Index()
打印结果,差不多1s 时间
当然 Promise.all() 成功回调时间已最长的接口返回时间为准,如果把 p2的 定时改成 2s 那么回调也会在2s之后打印输出
所以说,在需要同时发送多个请求且需要都执行成功才能去渲染界面时,我们便可以使用Promise.all() 来节省我们的请求时间,提升性能。
更多方法:
静态方法 |
介绍说明 |
---|---|
Promise.all(iterable) | 这个方法返回一个新的promise对象,该promise对象在iterable参数对象里所有的promise对象都成功的时候才会触发成功,一旦有任何一个iterable里面的promise对象失败则立即触发该promise对象的失败。这个新的promise对象在触发成功状态以后,会把一个包含iterable里所有promise返回值的数组作为成功回调的返回值,顺序跟iterable的顺序保持一致;如果这个新的promise对象触发了失败状态,它会把iterable里第一个触发失败的promise对象的错误信息作为它的失败错误信息。Promise.all方法常被用于处理多个promise对象的状态集合。(可以参考jQuery.when方法---译者注) |
Promise.allSettled(iterable) | 等到所有promises都已敲定(settled)(每个promise都已兑现(fulfilled)或已拒绝(rejected))。 返回一个promise,该promise在所有promise完成后完成。并带有一个对象数组,每个对象对应每个promise的结果。 |
Promise.any(iterable) | 接收一个Promise对象的集合,当其中的一个 promise 成功,就返回那个成功的promise的值。 |
Promise.race(iterable) | 当iterable参数里的任意一个子promise被成功或失败后,父promise马上也会用子promise的成功返回值或失败详情作为参数调用父promise绑定的相应句柄,并返回该promise对象。 |
Promise.reject(reason) | 返回一个状态为失败的Promise对象,并将给定的失败信息传递给对应的处理方法 |
Promise.resolve(value) | 返回一个状态由给定value决定的Promise对象。如果该值是thenable(即,带有then方法的对象),返回的Promise对象的最终状态由then方法执行决定;否则的话(该value为空,基本类型或者不带then方法的对象),返回的Promise对象状态为fulfilled,并且将该value传递给对应的then方法。通常而言,如果您不知道一个值是否是Promise对象,使用Promise.resolve(value) 来返回一个Promise对象,这样就能将该value以Promise对象形式使用。 |
参考
MDN 关于 Promise.all()
更多使用相关可参考
MDN 关于 Promise
完了。