概述
promise
为 js 提供了并发异步
能力,有回调地狱
的问题。async/await
可以使一批promise
按同步依次
的模式去执行(一些接口依赖场景是有此需求的),解决回调地狱
的问题。promise.all
可以等待一批promise
任务全部执行完成
后返回,一并返回结果集合
,适合子任务无相互依赖
,但后续任务
需依赖前多个子任务的数据结果
的场景。
Promise / Promise.all
Promise
提供了异步接口,搭配 resolve/reject
可以很方便的让业务代码并发执行。
function promiseReq(url) {
return new Promise((resolve, reject) => {
fetch(url).then((res) => {
resolve(res)
}).catch((e) => {
reject(e)
})
})
}
//
promiseReq(url1)
.then(res => console.log(res))
.catch(e => console.error(e))
promiseReq(url2)
.then(res => console.log(res))
.catch(e => console.error(e))
console.log("promise1 promise2 execute")
Promise.all
则是并发执行任务集合,且等待所有的任务执行完成后,一并返回结果集。
async / await
async
正如其名,用于定义一个异步方法,它会自动将方法封装成一个 Promise
返回,并且使用 return
代表 resolve
,throw
代表 reject
。
async function asyncFoo() {
if (Math.floor(Math.random() * 10) > 5) {
return "asyncFoo resolved"
}
throw "asyncFoo rejected"
}
console.log(asyncFoo() instanceof Promise)
asyncFoo().then((res) => {
console.log(res)
}).catch((e) => {
console.error(e)
})
但日常开发中我们并不会单独使用 async
,而是搭配 await
去同步多个 promise
任务。await
的作用就是让 Promise
的异步回调降维至同步模式。
场景1 - 接口并发执行且数据结果汇总
当需要等待一批接口的数据全部返回后,才可以继续执行后面的接口时,则可以使用 Promise.all
来处理 一批任务
。其会 并发
执行 任务集合
中的 Promise 任务
,等待所有的任务执行完成后,汇总结果并返回(结果数组)。
比如刷新用户信息接口,1.请求基础数据 2.请求订单数据 3.请求邀请数据 4.刷新完成,4 要等待 1、2、3 全部执行完成后才可执行
,那就很适用 Promise.all([1,2,3]).then((res) => {4})
的场景。
function promiseEnum(countDown) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("promiseEnum countDown " + countDown)
}, countDown * 1000)
})
}
Promise.all([promiseEnum(1), promiseEnum(2), promiseEnum(3)])
.then((values) => {
// 等待 1 2 3 并发执行完成
console.log("Promise.all values", values)
promiseEnum(4).then((res4) => {
console.log(res4)
})
})
场景2 - 接口顺序依赖执行
试想一下,有4个数据接口,后者依赖前者返回的结果才能继续执行,如果使用传统的 Promise
,那大概就是
// callback hell
promiseReq(url1).then((res1) => {
promiseReq(url2 + res1).then((res2) => {
promiseReq(url3 + res2).then((res3) => {
promiseReq(url4 + res3).then((res4) => {
console.log("promiseReq finished")
}).catch(err => console.error(err))
}).catch(err => console.error(err))
}).catch(err => console.error(err))
}).catch(err => console.error(err))
使用 async/await
则可以友好的解决依赖回调问题,让代码以 同步
的风格编写和执行。
// 使用 async/await 则可以友好的解决依赖回调问题
async function promiseSyncReq() {
let res1 = await promiseReq(url1)
let res2 = await promiseReq(url2 + res1)
let res3 = await promiseReq(url3 + res2)
let res4 = await promiseReq(url4 + res3)
return res4
}
promiseSyncReq().then((res4) => {
console.log(res4)
}).catch(e => console.log(err))
async/await
的执行耗时等于各个 Prmoise
累计的总耗时(执行流本就是要串行,耗时自然是各接口的累计,回调模式也一样的)。
async function awaitAllPromise() {
let res1 = await promiseEnum(1)//阻塞等待 耗时1秒
let res2 = await promiseEnum(2)//阻塞等待 耗时2秒
let res3 = await promiseEnum(3)//阻塞等待 耗时3秒
let res4 = await promiseEnum(4)//阻塞等待 耗时4秒
//执行总耗时为各 Promise 耗时的累加
return [res1, res2, res3, res4]
}
组合使用
async/await
与 promise/promise.all
组合使用,灵活实现 部分任务并发执行
, 部分任务同步执行
。
async function batchExec() {
console.group("batchExec")
let startTime = new Date().getTime()
console.log("batchExec start", startTime)
// 等待 1,2,3 并发执行完成
let paralValues = await Promise.all([promiseEnum(1), promiseEnum(2), promiseEnum(3)])
let paralTime = new Date().getTime()
console.log("parallel 1,2,3 finished", paralTime, (paralTime - startTime) / 1000, paralValues)
// 再继续执行 4
let res4 = await promiseEnum(4)
let endTime = new Date().getTime()
console.log("batchExec end", endTime, (endTime - startTime) / 1000)
console.groupEnd("batchExec")
return [...paralValues, res4]
}
batchExec()
.then(res => console.log(res))
.catch(e => console.error(e))