要想实现自己的promise,首先我们要知道promise的用法,执行代码后出现的效果是什么。
我们先从最基本的用法开始:
const promise = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('Promise返回值')
},2000)
})
promise.then(res=>{
console.log('后输出',res)
})
console.log('先输出111')
我们根据这段代码,来梳理下思路:
- 先声明一个class类,我们叫做
MyPromise; MyPromise类 构造函数接收一个回调函数 做为参数,且该回调函数有两个参数 分别为resolve(成功)reject(失败),均为函数;MyPromise还有一个实例可调用的then 方法,该方法同样接收两个参数 分别为 成功的回调函数 和 失败的回调函数
接下来我们实现这个函数
class MyPromise {
constructor(fn) {
this.promiseState = 'pendding'; //设置初始状态
this.resolveFn = null; //保存then 方法中成功的回调
this.rejectFn = null; // 保存then 方法中失败的回调
fn(this.resolve, this.reject)
}
resolve(result) {
if(this.promiseState==='pendding'){
this.promiseState = 'fulfilled'
if (this.resolveFn) {
this.resolveFn(result)
}
}
}
reject(reason) {
if(this.promiseState==='pendding'){
this.promiseState = 'rejected'
if (this.rejectFn) {
this.rejectFn(reason)
}
}
}
then(resolve, reject) {
resolve && (this.resolveFn = resolve);
reject && (this.rejectFn = reject)
}
}
下面我们来测试一下上面写的MyPromise类:
//测试用例1 异步
const promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('Promise返回值')
}, 2000)
})
promise.then(res=>{
console.log('后输出',res)
})
console.log('先输出111')
运行上面的代码 发现 控制台报错,并不是我们想要的输出结果
Uncaught TypeError: Cannot read properties of undefined (reading 'PromiseState')
at resolve (<anonymous>:10:17)
at <anonymous>:36:9
从报错信息我们可以看出 在 执行resolve这个回调方法的时候 undefined 不能读取他的 PromiseState 属性
那么看一下我们定义的resolve方法里是 this.PromiseState 那么就是this是undefined 那么只能是this指向问题
解决class 的 this指向 一般会用箭头函数或者bind,在这里我们就可以使用bind来绑定this,那么只需要将MyPromise类的构造函数constructor 中的this.resolve和this.reject后加上.bind(this)就可以了。
我们改造后的构造方法就是下面这样子的
constructor(fn) {
this.promiseState = 'pendding'; //设置初始状态
this.resolveResult = null;
this.rejectReason = null;
fn(this.resolve.bind(this), this.reject.bind(this))
}
在执行上面的测试用例 发现可以正常运行 且控制台输出结果和 new Promise 时是一样的
我们知道 Promise 构造函数就是需要一个 函数, 这个函数可以是一个异步操作 同理也可以是一个同步执行的函数 这时候我们在测一下我们的 MyPromise
//测试用例2 同步
const promise = new MyPromise((resolve, reject) => {
resolve('Promise返回值')
})
promise.then(res => {
console.log('后输出', res)
})
console.log('先输出111')
这时候我们发现 只有then 方法后面的输出 并没有 then 方法里面内容的输出 且没有报错信息,说明我们调用then 方法传入的函数没有执行
重新梳理一下思路:
- 创建实例的时候 回调函数里会调用
MyPromise这个类的 resove 方法 这个方法里 我们改变了 实例的状态 从 pendding 状态 改为 fulfilled 状态 且 会立即改变 然后执行了 调用 then 方法时 赋值给 resolveFn 的方法 但是这时候还没有执行到调用 then 方法 - 我们创建完实例之后 调用 then 方法 这时候 我们把成功的回调和失败的回调分别赋值给 resolveFn 和 rejectFn 但是没有调用
那么问题就很清晰了 我们第一步执行 resolveFn 这个方法的时候 回调函数还没有放进去 那么我们的回调函数肯定不会被调用
解决方法随之 也出来了 我们在 then 方法里加判断 当不是 pendding 状态的时候直接调用回调函数
then(resolve, reject) {
if(this.promiseState === 'pendding'){
resolve && (this.resolveFn = resolve);
reject && (this.rejectFn = reject)
}else if(this.promiseState === 'fulfilled'){
resolve()
}else if(this.promiseState === 'rejected'){
reject()
}
}
执行上面的 测试用例2 发现 输出顺序不对 且 返回值是没有的
输出顺序不对说明then方法没有异步执行,没有返回值我们就在实例上面加一个 保存执行结果的属性 修改后的 MyPromise 也就是这样子的
class MyPromise {
constructor(fn) {
this.promiseState = 'pendding'; //设置初始状态
this.resolveFn = null; //保存then 方法中成功的回调
this.rejectFn = null; // 保存then 方法中失败的回调
this.resolveResult = null;
this.rejectReason = null;
fn(this.resolve.bind(this), this.reject.bind(this))
}
resolve = (result) => {
if (this.promiseState === 'pendding') {
this.promiseState = 'fulfilled'
this.resolveResult = result;
if (this.resolveFn) {
this.resolveFn(result)
}
}
}
reject(reason) {
if (this.promiseState === 'pendding') {
this.promiseState = 'rejected'
this.rejectReason = reason;
if (this.rejectFn) {
this.rejectFn(reason)
}
}
}
then(resolve, reject) {
setTimeout(() => {
if (this.promiseState === 'pendding') {
resolve && (this.resolveFn = resolve);
reject && (this.rejectFn = reject)
} else if (this.promiseState === 'fulfilled') {
resolve(this.resolveResult)
} else if (this.promiseState === 'rejected') {
reject(this.rejectReason)
}
})
}
}