先实现一个最简易的Promise类
class MyPromise {
constructor(executor) {
this.state = 'padding'//有三种状态pending、fulfilled、rejected
this.value = null
// executor 是一个执行器,进入会立即执行
// 并传入resolve和reject方法
executor(this.resolve.bind(this), this.reject.bind(this))
}
// 将状态变成成功
resolve(val) {
this.state = 'fulfilled'
this.value = val
}
// 将状态变成失败
reject(val) {
this.state = 'rejected'
this.value = val
}
}
简单测试一波
const p1 = new MyPromise((resolve, reject) => {
resolve('success')
})
console.log(p1) // MyPromise { state: 'fulfilled', value: '成功' }
const p2 = new MyPromise((resolve, reject) => {
reject('fail')
})
console.log(p2) // MyPromise { state: 'rejected', value: 'fail' }
Promise状态变更后不能再修改
上面没啥问题,再看下面
const p3 = new MyPromise((resolve, reject) => {
resolve('success')
reject('fail')
})
console.log(p3) // MyPromise { state: 'rejected', value: 'fail' }
状态经过resolve、reject之后是依据最后一个为准,我们应该让Promise状态变更后不能再修改:
// 将状态变成成功
resolve(val) {
if (this.state !== 'padding') return
this.state = 'fulfilled'
this.value = val
}
// 将状态变成失败
reject(val) {
if (this.state !== 'padding') return
this.state = 'rejected'
this.value = val
}
再次测试,完美通过
const p3 = new MyPromise((resolve, reject) => {
resolve('success')
reject('fail')
})
console.log(p3) // MyPromise { state: 'fulfilled', value: 'success' }
捕获executor函数错误,并且rejected
我们知道用户传入的executor可能会运行报错,抛出错误的时候我们需要把状态修改为rejected
const p4 = new MyPromise(() => {
throw ('fail')
})
console.log(p4) // MyPromise { state: 'rejected', value: 'fail' }
那么我们try catch包装一下
try {
executor(this.resolve.bind(this), this.reject.bind(this))
} catch (error) {
this.reject(error)
}
实现then方法
// 传入两个参数:成功回调、失败回调,并且设置默认值
then(onFulfilled = val => val, onRejected = val => { throw val }) {
if (this.state === 'fulfilled') {
onFulfilled(this.value)
} else if (this.state === 'rejected') {
onRejected(this.value)
}
}
简单测试,完美通过
const p5 = new MyPromise((resolve, reject) => {
resolve('success')
}).then(res => console.log(res))//success
then支持在异步调用resolve或者reject后执行
以下暂不支持
const p6 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('success')
});
}).then(res => console.log(res))//没有打印
那么我们应该如何支持呢?在then函数调用的时候还没有执行过resolve,此时的状态为padding。我们先把回调函数存起来,然后在改变promise状态的处理函数里面调用存起来的函数即可。
实现如下:
then(onFulfilled = val => val, onRejected = val => { throw val }) {
if (this.state === 'fulfilled') {
onFulfilled(this.value)
} else if (this.state === 'rejected') {
onRejected(this.value)
// 此时的状态为padding
} else {
this.onFulfilled = onFulfilled
this.onRejected = onRejected
}
}
// 将状态变成成功
resolve(val) {
if (this.state !== 'padding') return
this.state = 'fulfilled'
this.value = val
// 如果有存起来的成功回调,那就执行
this.onFulfilled && this.onFulfilled(val)
}
// 将状态变成失败
reject(val) {
if (this.state !== 'padding') return
this.state = 'rejected'
this.value = val
// 如果有存起来的失败回调,那就执行
this.onRejected && this.onRejected(val)
}
执行示例,完美通过
const p7 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('success')
});
}).then(res => console.log(res))//success
支持多个then回调
但是会有以下问题:
const p8 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve()
});
})
p8.then(res => console.log(111))
p8.then(res => console.log(222))
p8.then(res => console.log(333))//333
我们看到只打印了333,前面的111、222都没有打印。其实是回调函数最终只指向了最后一个333的回调函数,那么我们可以用一个数组将回调函数存起来。 说干就干:
class MyPromise {
constructor(executor) {
this.state = 'padding'//有三种状态pending、fulfilled、rejected
this.value = null
this.onFulfilledLists = []
this.onRejectedLists = []
// executor 是一个执行器,进入会立即执行
// 并传入resolve和reject方法
try {
executor(this.resolve.bind(this), this.reject.bind(this))
} catch (error) {
this.reject(error)
}
}
// 将状态变成成功
resolve(val) {
if (this.state !== 'padding') return
this.state = 'fulfilled'
this.value = val
// 如果有存起来的成功回调,那就执行
while (this.onFulfilledLists.length) {
// 依据先进先出原则,截取第一个回调执行
this.onFulfilledLists.shift().call(this, val)
}
}
// 将状态变成失败
reject(val) {
if (this.state !== 'padding') return
this.state = 'rejected'
this.value = val
// 如果有存起来的失败回调,那就执行
while (this.onRejectedLists.length) {
// 依据先进先出原则,截取第一个回调执行
this.onRejectedLists.shift().call(this, val)
}
}
// 传入两个参数:成功回调、失败回调,并且设置默认值
then(onFulfilled = val => val, onRejected = val => { throw val }) {
if (this.state === 'fulfilled') {
onFulfilled(this.value)
} else if (this.state === 'rejected') {
onRejected(this.value)
// 此时的状态为padding
} else {
this.onFulfilledLists.push(onFulfilled)
this.onRejectedLists.push(onRejected)
}
}
}
123全部打印出来
const p9 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve()
});
})
p9.then(res => console.log(111))//111
p9.then(res => console.log(222))//222
p9.then(res => console.log(333))//333
then支持链式调用
显然,then返回的也是一个promise
then(onFulfilled = val => val, onRejected = val => { throw val }) {
return new MyPromise((resolve, reject) => {
// 为了方便,我们创建一个统一处理的函数
const middleFunc = fn => {
//利用 try catch捕获错误
try {
const result = fn.call(this, this.value)
// 如果then返回的是一个promise那就继续链式调用
if (result && result instanceof MyPromise) {
result.then(resolve, reject)
// 如果什么也没返回或者返回一个非Promise,那就包装成promise
} else {
resolve(result)
}
} catch (error) {
reject(error)
}
}
if (this.state === 'fulfilled') {
middleFunc(onFulfilled)
} else if (this.state === 'rejected') {
middleFunc(onRejected)
// 此时的状态为padding
} else {
this.onFulfilledLists.push(middleFunc.bind(this, onFulfilled))
this.onRejectedLists.push(middleFunc.bind(this, onRejected))
}
})
}
完美通过测试:
const p10 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve()
});
}).then(res => console.log(111))//111
.then(res => console.log(222))//222
.then(res => console.log(333))//333
异步执行promise
new MyPromise(resolve => {
resolve(111)
}).then(res => console.log(res))
console.log(222)
//打印结果
//111
//222
我们对then继续改造
then(onFulfilled = val => val, onRejected = val => { throw val }) {
return new MyPromise((resolve, reject) => {
// 为了方便,我们创建一个统一处理的函数
const middleFunc = fn => {
// 创建一个微任务
queueMicrotask(() => {
//利用 try catch捕获错误
try {
const result = fn.call(this, this.value)
// 如果then返回的是一个promise那就继续链式调用
if (result && result instanceof MyPromise) {
resolve.then(resolve, reject)
// 如果什么也没返回或者返回一个非Promise,那就包装成promise
} else {
resolve(result)
}
} catch (error) {
reject(error)
}
})
}
if (this.state === 'fulfilled') {
middleFunc(onFulfilled)
} else if (this.state === 'rejected') {
middleFunc(onRejected)
// 此时的状态为padding
} else {
this.onFulfilledLists.push(middleFunc.bind(this, onFulfilled))
this.onRejectedLists.push(middleFunc.bind(this, onRejected))
}
})
}
再次验证:
new MyPromise(resolve => {
resolve(111)
}).then(res => console.log(res))
console.log(222)
//打印结果
//222
//111
不能重复调用自己
使用原生 Promise 执行这个代码,会报类型错误
const p1 = new Promise((resolve, reject) => {
resolve(100)
}).then(value => {
console.log(value)
return p1
})
//打印
//100
//Uncaught (in promise) TypeError: Chaining cycle detected for promise #<Promise>
我们对then方法进行改造:
then(onFulfilled = val => val, onRejected = val => { throw val }) {
const p = new MyPromise((resolve, reject) => {
// 为了方便,我们创建一个统一处理的函数
const middleFunc = fn => {
// 创建一个微任务
queueMicrotask(() => {
//利用 try catch捕获错误
try {
const result = fn.call(this, this.value)
if (p === result) {
throw new TypeError('Chaining cycle detected for promise #<Promise>')
}
// 如果then返回的是一个promise那就继续链式调用
if (result && result instanceof MyPromise) {
result.then(resolve, reject)
// 如果什么也没返回或者返回一个非Promise,那就包装成promise
} else {
resolve(result)
}
} catch (error) {
reject(error)
// 创建一个宏任务继续往上抛错
setTimeout(() => {
throw error
})
}
})
}
if (this.state === 'fulfilled') {
middleFunc(onFulfilled)
} else if (this.state === 'rejected') {
middleFunc(onRejected)
// 此时的状态为padding
} else {
this.onFulfilledLists.push(middleFunc.bind(this, onFulfilled))
this.onRejectedLists.push(middleFunc.bind(this, onRejected))
}
})
return p
}
实现catch方法
catch(onRejected) {
return this.then(null, onRejected)
}
测试一下:
new MyPromise(() => {
throw 'fail'
}).catch(console.log) //fail
实现静态resolve和reject方法
static resolve(data) {
return new MyPromise(resolve => {
resolve(data)
})
}
static reject(data) {
return new MyPromise((resolve, reject) => {
reject(data)
})
}
测试一下:
MyPromise.resolve('successs') //MyPromise {state: "fulfilled", value: "successs", onFulfilledLists: Array(0), onRejectedLists: Array(0)}
MyPromise.reject('fail') //MyPromise {state: "rejected", value: "fail", onFulfilledLists: Array(0), onRejectedLists: Array(0)}
但是会有以下问题:
MyPromise.resolve(MyPromise.reject('fail')) //MyPromise {state: "fulfilled", value: MyPromise, onFulfilledLists: Array(0), onRejectedLists: Array(0)}
展开以后我们发现value是一个状态为rejected的promise
这显然不符合我们的预期:
下面我们开始对静态resolve方法传入的是个promise进行改造:
static resolve(data) {
// 如果传入的是个promise那就直接返回
if (data instanceof MyPromise) {
return data
}
return new MyPromise(resolve => {
resolve(data)
})
}
测试通过:
MyPromise.resolve(MyPromise.reject('fail')) //MyPromise {state: "rejected", value: "fail", onFulfilledLists: Array(0), onRejectedLists: Array(0)}
完整代码
class MyPromise {
constructor(executor) {
this.state = 'padding'//有三种状态pending、fulfilled、rejected
this.value = null
this.onFulfilledLists = []
this.onRejectedLists = []
// executor 是一个执行器,进入会立即执行
// 并传入resolve和reject方法
try {
executor(this.resolve.bind(this), this.reject.bind(this))
} catch (error) {
this.reject(error)
}
}
// 将状态变成成功
resolve(val) {
if (this.state !== 'padding') return
this.state = 'fulfilled'
this.value = val
// 如果有存起来的成功回调,那就执行
while (this.onFulfilledLists.length) {
// 依据先进先出原则,截取第一个回调执行
this.onFulfilledLists.shift().call(this, val)
}
}
// 将状态变成失败
reject(val) {
if (this.state !== 'padding') return
this.state = 'rejected'
this.value = val
// 如果有存起来的失败回调,那就执行
while (this.onRejectedLists.length) {
// 依据先进先出原则,截取第一个回调执行
this.onRejectedLists.shift().call(this, val)
}
}
// 传入两个参数:成功回调、失败回调,并且设置默认值
then(onFulfilled = val => val, onRejected = val => { throw val }) {
const p = new MyPromise((resolve, reject) => {
// 为了方便,我们创建一个统一处理的函数
const middleFunc = fn => {
// 创建一个微任务
queueMicrotask(() => {
//利用 try catch捕获错误
try {
const result = fn.call(this, this.value)
if (p === result) {
throw new TypeError('Chaining cycle detected for promise #<Promise>')
}
// 如果then返回的是一个promise那就继续链式调用
if (result && result instanceof MyPromise) {
result.then(resolve, reject)
// 如果什么也没返回或者返回一个非Promise,那就包装成promise
} else {
resolve(result)
}
} catch (error) {
reject(error)
// 创建一个宏任务继续往上抛错
setTimeout(() => {
throw error
})
}
})
}
if (this.state === 'fulfilled') {
middleFunc(onFulfilled)
} else if (this.state === 'rejected') {
middleFunc(onRejected)
// 此时的状态为padding
} else {
this.onFulfilledLists.push(middleFunc.bind(this, onFulfilled))
this.onRejectedLists.push(middleFunc.bind(this, onRejected))
}
})
return p
}
catch(onRejected) {
return this.then(null, onRejected)
}
static resolve(data) {
// 如果传入的是个promise那就直接返回
if (data instanceof MyPromise) {
return data
}
return new MyPromise(resolve => {
resolve(data)
})
}
static reject(data) {
return new MyPromise((resolve, reject) => {
reject(data)
})
}
}
疑问
最后给大家留个疑问,为什么静态reject方法不跟着resolve一起改造?
MyPromise.reject(MyPromise.resolve('success')) //打印的是什么?