Promise内置API原理及实现(含async,await)
文章目录
1、Promise.all
promise.all
接收一个Promise数组,数组中如有非Promise项,则此项当做成功
如果所有Promise都成功,则返回成功结果数组
如果有一个Promise失败,则返回这个失败结果
function all(PromiseArr){
// 返回的结果数组
let res = []
// 记录完成了多少个promise
let count = 0
// Promise.all 返回一个promise结果数组
return new Promise((resolve,reject)=>{
// 增加完成的结果数组
const addRes = (index,value)=>{
res[index] = value
count++
// 当所有promise都完成后才处理
if(count === PromiseArr.length) resolve(res)
}
// 循环遍历promise数组
PromiseArr.forEach((item,index)=>{
// 如果传来的是promise 则处理结果后添加到结果中
if(item instanceof Promise){
item.then(res=>addRes(index,res),err=>reject(err))
}else{
// 如果传的不是promise则直接加进结果中
addRes(index,item)
}
})
})
}
2、Promise.race
rece:
接收一个Promise数组,数组中如有非Promise项,则此项当做成功
哪个Promise最快得到结果,就返回那个结果,无论成功失败
function race(PromiseArr){
return new Promise((resolve,reject)=>{
PromiseArr.forEach((promise,index)=>{
// 数组里的promise处理后返回
if(promise instanceof Promise){
promise.then(res=>resolve(res),err=>reject(err))
}else{
//如果不是promise 则直接返回
// 加上queueMicrotask,让两个任务都进入微任务中,可以防止,如果传数值,在resolve后面,却输出数值
queueMicrotask(()=>resolve(promise))
}
})
})
}
3、Promise.allSettled
Promise.allSettled
接收一个Promise数组,数组中如有非Promise项,则此项当做成功
把每一个Promise的结果,集合成数组返回
function allSettled(PromiseArr){
return new Promise(resolve=>{
let res = []
let count = 0
// 定义一个处理结果的函数
const addRes = (status,value,index)=>{
// 作为处理对象的函数
let obj = {}
if(status === 'fulfilled') obj = {status,value}
else obj = {status,reason:value}
res[index] = obj
count++
// 当全部处理完成就返回结果
if(count === PromiseArr.length) resolve(res)
}
// 遍历待处理的数组依次添加到结果中
PromiseArr.forEach((item,index)=>{
if(item instanceof Promise){
item.then(res=>{
addRes('fulfilled',res,index)
},err=>{
addRes('rejected',err,index)
})
}else{
addRes('fulfilled',item,index)
}
})
})
}
// polyfill 处理 方法二
function allSettledPolyfill(PromiseArr){
const success = value=>({ status:'fulfilled',value})
const reason = reason=>({ status:'rejected',reason})
const convertedPromise = PromiseArr.map(p=>Promise.resolve(p).then(success,reason))
return Promise.all(convertedPromise)
}
4、Promise.any
Promise.any
只要其中的一个 promise 成功,就返回那个已经成功的 promise 。
如果可迭代对象中没有一个 promise 成功(即所有的 promises 都失败/拒绝),就返回一个失败的 promise 和AggregateError类型的实例,
它是 Error 的一个子类,用于把单一的错误集合在一起。
function any(PromiseArr){
return new Promise((resolve,reject)=>{
let failArr = []
const addFail = (index,fail)=>{
failArr[index] = fail
if(failArr.length === PromiseArr.length) reject(fail)
}
PromiseArr.forEach((item,index)=>{
if(item instanceof Promise){
item.then(res=>{resolve(res)},err=>addFail(index,item))
}else{
queueMicrotask(()=>{resolve(item)})
}
})
})
}
5、Promise.finally
Promise.finally
Promise中无论是否成功,都会执行
Promise.prototype.myfinally = function(callback){
// 自主想法实现finally同步,与原本一样即没有进入微任务,而当同步任务执行
callback()
return this
}
// 文章写法
// return this.then(res=>{
// callback()
// return res
// })
Async、await 的实现
使用ES6中的generator生成器,及yield关键字传参调用实现
// 模拟异步任务
function fn(num) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(num * 2)
}, 1000)
})
}
// generator 生成器函数,yield关键字,传参调用
function* gen() {
const num1 = yield fn(1)
// console.log((num1));
const num2 = yield fn(num1)
// console.log((num2));
const num3 = yield fn(num2)
// console.log((num3));
return num3
}
function generatorToAsync(generatorFn) {
return function () {
const gen = generatorFn.apply(this, arguments) // gen有可能传参
// 返回一个Promise
return new Promise((resolve, reject) => {
function go(key, arg) {
let res
try {
res = gen[key](arg) // 这里有可能会执行返回reject状态的Promise
} catch (error) {
return reject(error) // 报错的话会走catch,直接reject
}
// 解构获得value和done
const { value, done } = res
if (done) {
// 如果done为true,说明走完了,进行resolve(value)
return resolve(value)
} else {
// 如果done为false,说明没走完,还得继续走
// value有可能是:常量,Promise,Promise有可能是成功或者失败
return Promise.resolve(value).then(val => go('next', val), err => go('throw', err))
}
}
go("next") // 第一次执行
})
}
}
测试代码:
// 测试代码
const p1 = generatorToAsync(gen)
p1().then(res => {
console.log(res);
},err=>{
console.log(err);
})
// async await 写法
async function asyncFn() {
const num1 = await fn(1)
// console.log(num1) // 2
const num2 = await fn(num1)
// console.log(num2) // 4
const num3 = await fn(num2)
// console.log(num3) // 8
return num3
}
const asyncRes = asyncFn()
console.log(asyncRes) // Promise
asyncRes.then(res => console.log(res)) // 8
在外部调用next方法,会产生回调地狱
// 不用generatorToAsync处理函数的原生yield写法
// 存在回调地狱,所以建议使用generatorToAsync函数在内部调用next
const go = gen()
const {value} = go.next()
value.then(res=>{
console.log(res);
const {value} = go.next(res)
value.then(res=>{
console.log(res);
const {value} = go.next(res)
value.then(res=>{
console.log(res);
})
})
})