前言
手写自然不会要求写全, 只要实现基本的常用的几个api。我们要实现的几个功能如下
new Promise((resolve, reject)=>{
})
.then()
.catch()
Promise.resolve()
Promise.reject()
Promise.all()
Promise.race()
构造函数
- promise 有三个状态
- 状态一旦修改不可逆转 请根据以上两点查看下面代码
class MyPromise{
status = 'pending' // resolved rejected
value = undefined
reason = undefined
constructor(fn) {
const resolveHandler = (v) => {
if(this.status === 'pending') {
this.status = 'resolved'
this.value = v
}
}
const rejectHandler = (e) => {
if(this.status === 'pending') {
this.status = 'rejected'
this.reason = e
}
}
try {
fn(resolveHandler, rejectHandler)
} catch (error) {
rejectHandler(error)
}
}
}
then
- then 有两个入参, 第一个是resolve调用, 第二个是reject调用
- then会返回一个新的promise
请根据以上两条参考来查看以下代码
- 情况一: 传入的函数直接调用resolve
// 测试示例
new MyPromise((resolve, reject)=>{
resolve(100)
}).then(val=>{
console.log(val)
return 200
}).then(val=>{
console.log(val)
})
// 主体部分
then(successFn, errorFn){
successFn = typeof successFn === 'function' ? successFn : v=>v
errorFn = typeof errorFn === 'function' ? errorFn : e=> {throw e}
if(this.status === 'resolved'){
return new MyPromise((resolve, reject)=>{
try {
const val = successFn(this.value)
resolve(val)
} catch (error) {
reject(error)
}
})
}
}
- 情况二: 传入的函数直接调用reject, 实现和上面的基本一致
// 测试示例
new MyPromise((resolve, reject)=>{
reject(new Error('错误1'))
}).then(null, err=>{
console.log(err.message)
})
new MyPromise((resolve, reject)=>{
throw new Error('错误2')
resolve()
}).then(null, err=>{
console.log(err.message)
throw new Error('错误3')
}).then(null, err=>{
console.log(err.message)
return 200
}).then(val=>{console.log(val)})
// 主体部分
then(successFn, errorFn){
successFn = typeof successFn === 'function' ? successFn : v=>v
errorFn = typeof errorFn === 'function' ? errorFn : e=> {throw e}
if(this.status === 'rejected'){
return new MyPromise((resolve, reject)=>{
try {
const val = errorFn(this.reason)
resolve(val)
} catch (error) {
reject(error)
}
})
}
}
- 情况三: 传入的函数异步调用resolve 或 reject
- 执行then时, 还不知道成功还是失败, 所以放回的Promise也不能直接调用 resolve或reject
- 需要等待之前的promise返回结果再进行调用
// 测试示例
new MyPromise((resolve, reject)=>{
setTimeout(() => {
resolve(100)
}, 1000);
}).then(val=>{
console.log(val)
})
class MyPromise{
resolveCallbacks = []
rejectCallbacks = []
constructor(fn) {
const resolveHandler = (v) => {
if(this.status === 'pending') {
this.status = 'resolved'
this.value = v
this.resolveCallbacks.forEach(fn=>fn())
}
}
const rejectHandler = (e) => {
if(this.status === 'pending') {
this.status = 'rejected'
this.reason = e
this.rejectCallbacks.forEach(fn=>fn())
}
}
}
then(successFn, errorFn){
if(this.status === 'pending'){
return new MyPromise((resolve, reject)=>{
this.resolveCallbacks.push(()=>{
try {
const val = successFn(this.value)
resolve(val)
} catch (error) {
reject(error)
}
})
this.rejectCallbacks.push(()=>{
try {
const val = errorFn(this.reason)
resolve(val)
} catch (error) {
reject(error)
}
})
})
}
}
}
catch/Promise.resolve()/Promise.reject()
这个就很简单了, then中其实已经实现了catch的功能了
catch(errorFn){
return this.then(null, errorFn)
}
Promise.resolve
MyPromise.resolve = (val)=>{
return new MyPromise((resolve)=>{
resolve(val)
})
}
Promise.reject
MyPromise.reject = (err)=>{
return new MyPromise((resolve, reject)=>{
reject(err)
})
}
Promise.all
MyPromise.all = (promiseList = [])=>{
return new MyPromise((resolve, reject)=>{
const resList = []
let resIndex = 0
promiseList.forEach(p=>{
p.then(res=>{
resList.push(res)
resIndex++
if(resIndex === promiseList.length){
resolve(resList)
}
}).catch(err=>{
reject(err)
})
})
})
}
Promise.race
MyPromise.race = (promiseList = [])=>{
return new MyPromise((resolve, reject)=>{
promiseList.forEach(p=>{
p.then(res=>{
resolve(res)
}).catch(err=>{
reject(err)
})
})
})
}