一、写在前面
本文主要总结Promise
的相关知识,主要分为两个部分,一个是对于Promsie
的api
使用。另一个是对于手写Promise
。完全解决面试问题。Promise
主要分为三种状态,一个是pendding
,一个是fulfillled
,另一个是rejected
。
二、Promise api的使用
2.1、promise的then方法
//1、then中没有返回值,则会使用promise包裹undefined进行返回。
let promise = new Promise((resolve, reject) => {
resolve('hhhh')
}).then(res => {
console.log(res) //hhhh
}).then(ret => {
console.log(ret) //undefined
})
//2、如果直接使用return一个值,则会在外部包裹一层promise
let promise = new Promise((resolve, reject) => {
resolve("hhhh")
}).then(res => {
console.log(res) //hhhh
return "next one"
}).then(res => {
console.log(res) //next one
})
//3、如果直接return promise,则会将Promise返回的结果传递下去
let promise = new Promise((resolve, reject) => {
resolve("hhhh")
}).then(res => {
console.log(res) //hhhh
return new Promise((resolve, reject) => {
resolve("next one")
})
}).then(res => {
console.log(res) //next one
})
//4、也可以是thenable对象
let promise = new Promise((resolve, reject) => {
resolve("hhhh")
}).then(res => {
console.log(res) //hhhh
return {
then(resolve, reject) {
resolve("next one")
}
}
}).then(res => {
console.log(res) //next one
})
//5、如果一个promsie出现多个then则都是会执行的。
let promise = new Promise((resolve, reject) => {
resolve("hhhh")
})
promise.then(res => {
console.log(res + "第一个") //hhhh第一个
})
promise.then(res => {
console.log(res + "第二个") //hhhh第二个
})
2.2、catch方法
//1、直接通过new Error报错,导致阅读性差
let promise = new Promise((resolve, reject) => {
throw new Error('err message')
})
promise.then(res => {
console.log(res)
}, err => {
console.log(err.name) //Error
})
//2、把catch放在最后,如果整条promsie链路上存在错误,则就会执行catch函数中的内容。
let promise = new Promise((resolve, reject) => {
resolve('大家好')
// reject('er')
}).then(res => {
console.log(res) //大家好
return new Promise((resolve, reject) => {
// resolve('急急急')
reject('hhjhh')
})
}).catch(err => {
console.log(err) //hhjhh
})
//3、catch执行完之后也会返回一个promsie对象
let promise = new Promise((resolve, reject) => {
// resolve('hello world')
reject('message err')
})
promise.then(res => {
console.log(res)
}).catch(err => {
console.log(err) //message err
return 'hek'
}).then(ret => {
console.log(ret) //hek
}).catch(err => {
console.log(err)
})
2.3、finnally方法
let promise = new Promise((resolve, reject) => {
// resolve("大家")
reject('sss')
})
promise.then(res => {
console.log(res)
}).catch(err => {
console.log(err) //sss
}).finally(() => {
console.log('hello finnally') //hello finnally
})
//finally中的函数,在最后才执行
2.4、Promise.resolve()
//也就相当于
new Promise((resolve, reject) => {
resolve("hhhhh")
})
2.5、Promise.reject()
//也就相当于
new Promise((resolve, reject) => {
reject('hhhhh')
})
2.6、Promise.all
//1、Promise.all()中传入一个数组,并且数组中的元素可以默认可以转化为Promise,假如是字符串'12s',则会
//转化为new Promise((resolve, reject) => { resolve('12s') })
//2、Promise.all()传入的数组中,如果存在reject的,则直接执行catch中的回调函数,如果不存在reject的,则直接执行then。
//3、Promise.all如果出现错误的情况,则直接返回第一错误的内容。
例子一:
let promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('111')
}, 1000)
})
let promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('222')
}, 2000)
})
let promise3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('333')
}, 3000)
})
Promise.all([promise1, promise2, promise3]).then(res => {
console.log(res) //['111','222','333']
}).catch(err => {
console.log(err)
})
例子二:
let promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('111')
}, 1000)
})
let promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("222")
}, 2000)
})
let promise3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('333')
}, 3000)
})
Promise.all([promise1, promise2, promise3]).then(res => {
console.log(res)
}).catch(err => {
console.log(err) //222
})
2.7、Promise.allSettled
//Promise.allSettled返回的是状态对象。
let promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('111')
}, 1000)
})
let promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('222')
}, 2000)
})
let promise3 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('333')
}, 3000)
})
Promise.allSettled([promise1, promise2, promise3]).then(res => {
console.log(res)
})
/*
[
{ status: 'fulfilled', value: '111' },
{ status: 'fulfilled', value: '222' },
{ status: 'rejected', reason: '333' }
]
*/
2.8、Promise.race()
let promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('111')
}, 1000)
})
let promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('222')
}, 2000)
})
let promise3 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('333')
}, 3000)
})
Promise.race([promise1, promise2, promise3]).then(res => {
console.log(res)
}).catch(err => {
console.log('err' + err) //err111(并且也会等待三秒才会结束)
})
//race是拿到最先出来的结构,不论结果是resolve还是reject。
2.9、Promse.any
//1、Promise.any表示只要返回一个即可,如果全都是reject的,则直接执行catch中的回调函数
//2、Promise.any是在es12中新增的目前node可能不支持,所以需要在浏览器环境下执行。
let promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('111')
}, 1000)
})
let promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('222')
}, 2000)
})
let promise3 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('333')
}, 3000)
})
Promise.any([promise1,promise2, promise3]).then(res => {
console.log(res)
}).catch(err => {
console.log(err.errors) //['111','222','333']
})
三、手写Promise
// 定义三个常量
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_PENDDING = 'pendding'
const PROMISE_STATUS_REJECTED = 'rejected'
function execFunc(func, value, resolve, reject) {
try {
let res = func(value)
resolve(res)
} catch (err) {
reject(err)
}
}
class MyPromise {
constructor(exacutor) {
this.status = PROMISE_STATUS_PENDDING
this.reason = undefined
this.value = undefined
this.onFulfilledFns = []
this.onRejectedFns = []
const resolve = (value) => {
if (this.status === PROMISE_STATUS_PENDDING) {
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDDING) return
this.value = value
this.status = PROMISE_STATUS_FULFILLED
this.onFulfilledFns.forEach(fn => fn(this.value))
})
}
}
const reject = (reason) => {
if (this.status === PROMISE_STATUS_PENDDING) {
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDDING) return
this.reason = reason
this.status = PROMISE_STATUS_REJECTED
this.onRejectedFns.forEach(fn => fn(this.reason))
})
}
}
exacutor(resolve, reject)
}
then(onFulfilled, onRejected) {
onRejected = onRejected || (err => {
throw err
})
return new MyPromise((resolve, reject) => {
if (this.status === PROMISE_STATUS_FULFILLED) {
if (onFulfilled) execFunc(onFulfilled, this.value, resolve, reject)
}
if (this.status === PROMISE_STATUS_REJECTED) {
if (onRejected) execFunc(onRejected, this.reason, resolve, reject)
}
if (this.status === PROMISE_STATUS_PENDDING) {
if (onFulfilled) this.onFulfilledFns.push(() => {
execFunc(onFulfilled, this.value, resolve, reject)
})
if (onRejected) this.onRejectedFns.push(() => {
execFunc(onRejected, this.reason, resolve, reject)
})
}
})
}
// catch方法
catch (onRejected) {
return this.then(undefined, onRejected)
}
// finally方法
finnally(onFinial) {
this.then(() => {
onFinial()
}, () => {
onFinial()
})
}
// 实现MyPromise.resolve()方法
static resolve(value) {
return new MyPromise((resolve, reject) => {
resolve(value)
})
}
// 实现MyPromise.reject()方法
static reject(reason) {
return new MyPromise((resolve, reject) => {
reject(reason)
})
}
// 实现MyPromise.all()方法
static all(promises) {
return new MyPromise((resolve, reject) => {
let arr = []
promises.forEach(item => {
item.then(res => {
arr.push(res)
if (arr.length === promises.length) {
resolve(arr)
}
}, err => {
reject(err)
})
})
})
}
// 实现MyPromise.allSettle()
static allsettle(promises) {
return new MyPromise((resolve, reject) => {
let arr = []
promises.forEach(item => {
item.then(res => {
arr.push({
value: res,
status: PROMISE_STATUS_FULFILLED
})
if(arr.length === promises.length) {
resolve(arr)
}
}, err => {
arr.push({
value: err,
status: PROMISE_STATUS_REJECTED
})
if(arr.length === promises.length) {
resolve(arr)
}
})
})
})
}
// 实现MyPromise.race()方法
static race(promises) {
return new MyPromise((resolve, reject) => {
promises.forEach(item => {
item.then(res => {
resolve(res)
}, err => {
reject(err)
})
})
})
}
// 实现MyPromise.any()方法
static any(promises) {
return new MyPromise((resolve, reject) => {
let arr = []
promises.forEach(item => {
item.then(res => {
resolve(res)
}, err => {
arr.push(err)
if(arr.length === promises.length) {
reject(new AggregateError(arr))
}
})
})
})
}
}