实际上,Promise 有许多巧妙的高级用法,其中一些在 ALOVA 请求策略库中广泛使用。
ALOVA 是一个基于 Promise 的请求策略库,旨在帮助开发者更高效地进行 HTTP 请求处理。它通过高级的 Promise 技巧,实现了请求共享、缓存、批量请求等功能,从而简化了前端开发中的数据请求管理。
下面列举出一些。
串行执行 Promise 数组
例如,有一组需要串行执行的接口:
const p1 = () => Promise.resolve(1, console.log(1))
const p2 = () => Promise.resolve(2, console.log(2))
const p3 = () => Promise.resolve(3, console.log(3))
const pList = [p1, p2, p3]
/**
* 等价实现效果如下:
Promise.resolve().then(() => {
return p1()
}).then(res => {
return p2()
}).then(res => {
return p3()
})
*/
首先想到的使用 await:
runPList(pList)
async function runPList(pList) {
for (const p of pList) {
await p()
}
}
也可以使用 Promise 语法用 then 串起来顺序执行:
runPList(pList)
function runPList(pList) {
return pList.reduce((pre, cur) => pre.then(() => cur()), Promise.resolve())
}
串行并依赖前一个 Promise 的结果
如果后一个 Promise 的入参要依赖前一个 Promise 的结果:
const p4 = res => Promise.resolve(res + 4, console.log(res + 4))
const p5 = res => Promise.resolve(res + 5, console.log(res + 5))
const p6 = res => Promise.resolve(res + 6, console.log(res + 6))
const pList2 = [p4, p5, p6]
/**
* 等价实现效果如下:
Promise.resolve(0).then(res => {
return p1(res)
}).then(res => {
return p2(res)
}).then(res => {
return p3(res)
})
*/
解决方式跟上面差不多,只是多传递了个参数,重点是要生成统一格式的返回 Promise 的函数(p4、p5、p6):
runPList2(pList2)
function runPList2(pList) {
return pList.reduce((pre, cur) => pre.then(res => cur(res)), Promise.resolve(0))
}
实现 Koa2 洋葱模型中的 Promise
洋葱模型就是让 Promise 数组中的“中间件”能顺序处理,再按相反的顺序处理:
const p7 = async next => {
console.log(7)
await next()
console.log(77)
}
const p8 = async next => {
console.log(8)
await next()
console.log(88)
}
const p9 = async next => {
console.log(9)
await next()
console.log(99)
}
const pList3 = [p7, p8, p9]
/**
* 等价实现效果如下:
new Promise(async (resolve) => {
console.log(7)
await new Promise(async (resolve) => {
console.log(8)
await new Promise(async (resolve) => {
console.log(9)
await new Promise(async (resolve) => {
resolve()
})
console.log(99)
resolve()
})
console.log(88)
resolve()
})
console.log(77)
resolve()
})
*/
/**
* 立即执行函数简写效果:
(async function p7() {
console.log(7)
await Promise.resolve((async function p8() {
console.log(8)
await Promise.resolve((async function p9() {
console.log(9)
await Promise.resolve()
console.log(99)
})())
console.log(88)
})())
console.log(77)
})()
*/
首先我们要按顺序执行 pList,借助一个计数器 nextIndex 标识下一个执行的中间件的索引:
runPList3(pList)
function runPList3(pList) {
let nextIndex = 1
pList[0](next)
function next() {
const nextMiddleware = pList[nextIndex]
if (nextMiddleware) {
nextIndex++
nextMiddleware(next)
}
}
}
当然还要处理 next 之后的后置逻辑,我们必须返回一个 Promise 才能等待处理:
runPList3(pList)
function runPList3(pList) {
let nextIndex = 1
pList[0](next)
function next() {
const nextMiddleware = pList[nextIndex]
if (nextMiddleware) {
nextIndex++
// 这里添加一个 return ,使中间件函数的执行通过 Promise 从后向前连接
return nextMiddleware(next)
} else {
// 最后一个中间件的前置逻辑执行完成后,返回的 fulfilled Promise 将开始执行 next 之后的后置逻辑
return Promise.resolve()
}
}
}