手写实现一个Promise
一、实现思路
1、Promise的基本结构
首先我们先来看下Promise的基本结构 👀
const p = new Promise((resolve,reject) => {
resolve(1)
})
2、Promise的状态转换
Promise有三个状态:
😮 pending
(等待处理)
💖 fulfilled
(处理成功)
💢 rejected
(处理失败)
Promise 状态的改变是不可逆的,只能从 pending 转换到 fulfilled 或者从 pending 转换到 rejected.
当某个状态改变时,将执行then方法绑定的回调函数。
3、Promise的then方法
Promise
的then
方法接收两个参数。
- 第一个参数为
成功
时的回调函数 - 第二个参数为
失败
时的回调函数。
一个常常用到的语法是在
then
方法中返回一个新的Promise
。如果在回调函数中 return 了一个普通值,那么将会把这个值作为参数,传递给后面的then
方法的回调函数。
如果在回调函数中
return
了一个Promise
,那么下一个then
方法的回调函数将会等到这个Promise
执行完毕之后再执行,并且它的状态(成功或失败)也将作为参数,传递给后面的then
方法的回调函数。
4、Promise的链式调用
Promise 的链式调用是通过在每次 then 方法中返回一个新的 Promise 实例来实现的。
链式调用保证了在每一个 then 中返回普通值或 Promise 都可以被后面 then 的回调函数获取到。
5、Promise的错误捕获
在 then 方法中捕获错误有两种方式:
-
第一种方式是在每个
then
中使用try catch
捕获错误(不推荐,但这里我并没有实现catch方法
) -
第二种方式是使用
Promise
对象的catch
方法捕获错误。
二、具体实现(ts)
🐸 我们对Promise
的基本思路已经有了比较清晰的定义,接下来我们来实现具体的代码(取名为MyPromise
)。
1、MyPromise状态
首先定义一个枚举类,来定义MyPromise
的状态。
enum PromiseStatus {
OK = 'fulfilled',
LOADING = 'pending',
FAIlURE = 'rejected'
}
2.基本结构
回顾一下,
Promise
的使用,new
一个Promise
实例,然后传递一个函数
,这个函数会在Promise
实例创建的时候立即执行,并且接受两个参数,用来改变这个Promise的状态:resolve
和reject
。
const p = new Promise((resolve,reject) => {
resolveg(1)
})
我们来实现一下这个基本结构。
class MyPromise {
constructor(callback) {
callback(this.resolve, this.reject);
}
resolve = (value: any) => {
// 成功状态处理
};
reject = (errorValue: any) => {
// 失败状态处理
}
}
💦加点料,我们来实现一下
MyPromise
的状态转换。但在这之前,我们先来定义一下MyPromise
的状态和对应的值。
class MyPromise {
// 成功的值
value: any = void 0;
// 当前的状态 默认为等待状态
status = PromiseStatus.LOADING
// 失败的值
failureValue: any = void 0;
constructor(callback) {
callback(this.resolve, this.reject);
}
resolve = (value: any) => {
// 成功状态处理
};
reject = (errorValue: any) => {
// 失败状态处理
}
}
实现
resolve()
,只有当加载状态为pending
的时候,才能改变状态为fulfilled
或rejected
,并且把成功的值赋值给value
。
resolve = (value: any) => {
if (this.status === PromiseStatus.LOADING) {
this.value = value;
this.status = PromiseStatus.OK;
}
};
实现reject()
,与resolve()
类似。
reject = (errorValue: any) => {
if (this.status === PromiseStatus.LOADING) {
this.failureValue = errorValue;
this.status = PromiseStatus.FAIlURE;
}
};
3、then方法
现在我们已经实现了
MyPromise
的基本结构,接下来我们来实现then()
方法。在 then 方法中,主要处理了okCallback和errorCallback的执行及参数传递。
then(okCallback: any, errorCallback: any) {
// 如果状态为成功,执行成功回调
if (this.status === PromiseStatus.OK) {
okCallback(this.value);
}else if (this.status === PromiseStatus.FAIlURE) {
// 如果状态为失败,执行失败回调
errorCallback(this.failureValue);
}else if(this.status === PromiseStatus.LOADING){
// 如果还未完成
}
}
⚗️测试一下
const p = new MyPromise((resolve) => {
console.log(1);
resolve('ok')
})
p.then((value) => {
console.log(value)
}, () => { })
输出结果:
1
ok
😄 一切正常。
4、链式调用
在
then()
方法中,我们返回了一个新的MyPromise
实例,这样就可以实现链式调用了。
then(okCallback: any, errorCallback: any) {
const newMyPromise = new MyPromise((resolve, reject) => {
// 如果状态为成功,执行成功回调
if (this.status === PromiseStatus.OK) {
okCallback(this.value);
} else if (this.status === PromiseStatus.FAIlURE) {
// 如果状态为失败,执行失败回调
errorCallback(this.failureValue);
} else if (this.status === PromiseStatus.LOADING) {
// 如果还未完成
}
})
return newMyPromise
}
⚗️再测试一下
const p = new MyPromise((resolve) => {
console.log(1);
resolve('ok')
}).then((value) => {
console.log(value)
}, () => { })
⭐️输出结果:
1
ok
5、异步调用
现在的
MyPromise
实例是同步执行的,如果在回调中加入异步代码:
const p = new MyPromise((resolve) => {
console.log(1);
setTimeout(() => {
resolve('ok')
}, 1000)
}).then((value) => {
console.log(value)
}, () => { })
输出结果:
1
💢 可以看到,这个
ok
并没有打印。
接下来我们来实现异步调用,选用的微队列实现方式技术栈是
queueMicrotask
。
定义两个队列,分别用于存放成功和失败的回调。
// ...
// 成功的值
value: any = void 0;
// 当前的状态 默认为等待状态
status = PromiseStatus.LOADING
// 失败的值
failureValue: any = void 0;
// 成功的回调队列
okCallbackQueue: Function[] = [];
// 失败的回调队列
errorCallbackQueue: Function[] = [];
// ...
接着给
then()
加上异步的逻辑
then(okCallback: any, errorCallback: any) {
const newMyPromise = new MyPromise((resolve, reject) => {
// 如果状态为成功,执行成功回调
if (this.status === PromiseStatus.OK) {
okCallback(this.value);
} else if (this.status === PromiseStatus.FAIlURE) {
// 如果状态为失败,执行失败回调
errorCallback(this.failureValue);
} else if (this.status === PromiseStatus.LOADING) {
// 如果还未完成
this.okCallbackQueue.push(okCallback);
this.errorCallbackQueue.push(errorCallback);
}
})
return newMyPromise
}
然后是
resolve
和reject
的异步逻辑
resolve = (value: any) => {
if (this.status === PromiseStatus.LOADING) {
this.value = value;
this.status = PromiseStatus.OK;
while (this.okCallbackQueue.length) {
this.okCallbackQueue.shift()!();
}
}
};
reject = (errorValue: any) => {
if (this.status === PromiseStatus.LOADING) {
this.failureValue = errorValue;
this.status = PromiseStatus.FAIlURE;
while (this.errorCallbackQueue.length) {
this.errorCallbackQueue.shift()!();
}
}
};
//这里的`!`是因为`shift()`可能返回`undefined`,所以加上`!`告诉ts,这里一定有值
this.okCallbackQueue.shift()!();
this.errorCallbackQueue.shift()!()
⚗️再测试一下
const p = new MyPromise((resolve) => {
console.log(1);
setTimeout(() => {
resolve('ok')
}, 1000)
}).then((value) => {
console.log(value)
}, () => { })
输出结果:
1
ok
😄 完美!
还有一种情况需要处理,当连续的链式调用
then
,并且不带参数:
const p = new MyPromise((resolve) => {
console.log(1);
resolve('ok')
}).then() // ts会报错,因为then()的参数是必填的
.then()
.then()
.then()
.then((value) => {
console.log(value)
},() => {})
输出结果:
1
👀
'ok'
没有打印,这是因为调用then()
之后的返回值没有处理。 接着来吧!
首先处理ts报错的问题,给
then
的参数加上默认值
then(okCallback: any = (value: any) => value, errorCallback: any = (errorValue: any) => { throw errorValue }) {
// ...
}
然后参数归一化
then(okCallback: any = (value: any) => value, errorCallback: any = (errorValue: any) => { throw errorValue }) {
if (typeof okCallback !== 'function') {
okCallback = (value: any) => value
}
if (typeof errorCallback !== 'function') {
errorCallback = (errorValue: any) => { throw errorValue }
}
// ...
}
处理
then()
的返回值,我们写一个辅助函数。
returnValuePromiseManage(result: any, resolve: Function, reject: Function) {
if (result instanceof MyPromise) {
// then返回的是一个MyPromise 调用then
result.then(resolve, reject);
} else {
// 不返回或者普通值
resolve(result)
}
}
修改
then()
then(okCallback: any = (value: any) => value, errorCallback: any = (errorValue: any) => { throw errorValue }) {
// 兼容js
if (typeof okCallback !== 'function') {
okCallback = (value: any) => value
}
if (typeof errorCallback !== 'function') {
errorCallback = (errorValue: any) => { throw errorValue }
}
const newMyPromise = new MyPromise((resolve, reject) => {
// 如果状态为成功,执行成功回调
if (this.status === PromiseStatus.OK) {
const result = okCallback(this.value);
this.returnValuePromiseManage(result, resolve, reject);
} else if (this.status === PromiseStatus.FAIlURE) {
// 如果状态为失败,执行失败回调
const result = errorCallback(this.failureValue);
this.returnValuePromiseManage(result, resolve, reject);
} else if (this.status === PromiseStatus.LOADING) {
// 如果还未完成
this.okCallbackQueue.push(okCallback);
this.errorCallbackQueue.push(errorCallback);
}
})
return newMyPromise
}
再测试一下
const p = new MyPromise((resolve) => {
console.log(1);
resolve('ok')
}).then()
.then()
.then()
.then()
.then((value) => {
console.log(value)
}, () => { })
输出结果:
1
ok
😄 完美!
接着我们处理一下then()
中返回自身的情况 ,在Promise/A+规范中,规定了这种情况下应该抛出一个错误。
const p = new Promise((resolve) => {
resolve(1)
})
const p1 = p.then(() => {
return p1
})
// Uncaught (in promise) TypeError: Chaining cycle detected for promise #<Promise>
修改一下刚刚写的辅助函数
returnValuePromiseManage(newPromise: MyPromise, result: any, resolve: Function, reject: Function) {
if (newPromise === result) {
// 这里简单的打印一下错误信息
const msg = 'Chaining cycle detected for promise #<MyPromise>';
console.error(msg)
reject(new TypeError(msg))
}
if (result instanceof MyPromise) {
// then返回的是一个MyPromise 调用then
result.then(resolve, reject);
} else {
// 不返回或者普通值
resolve(result)
}
}
修改
then()
then(okCallback: any = (value: any) => value, errorCallback: any = (errorValue: any) => { throw errorValue }) {
// 兼容js
if (typeof okCallback !== 'function') {
okCallback = (value: any) => value
}
if (typeof errorCallback !== 'function') {
errorCallback = (errorValue: any) => { throw errorValue }
}
const newMyPromise = new MyPromise((resolve, reject) => {
// 如果状态为成功,执行成功回调
if (this.status === PromiseStatus.OK) {
const result = okCallback(this.value);
this.returnValuePromiseManage(newMyPromise, result, resolve, reject);
} else if (this.status === PromiseStatus.FAIlURE) {
// 如果状态为失败,执行失败回调
const result = errorCallback(this.failureValue);
this.returnValuePromiseManage(newMyPromise, result, resolve, reject);
} else if (this.status === PromiseStatus.LOADING) {
// 如果还未完成
this.okCallbackQueue.push(okCallback);
this.errorCallbackQueue.push(errorCallback);
}
})
return newMyPromise
}
由于这里的需要
newMyPromise
,但这里直接传入会报错
// Uncaught SyntaxError: Missing initializer in const declaration
所以我们需要把处理返回值的和执行okCallback的逻辑放到
微队列
中去执行,还需要处理异常,我这里就直接使用try
捕获
then(okCallback: any = (value: any) => value, errorCallback: any = (errorValue: any) => { throw errorValue }) {
if (typeof okCallback !== 'function') {
okCallback = (value: any) => value
}
if (typeof errorCallback !== 'function') {
errorCallback = (errorValue: any) => { throw errorValue }
}
const newMyPromise = new MyPromise((resolve, reject) => {
// 如果状态为成功,执行成功回调
if (this.status === PromiseStatus.OK) {
queueMicrotask(() => {
try {
const result = okCallback(this.value);
this.returnValuePromiseManage(newMyPromise, result, resolve, reject);
} catch (e) {
reject(e)
}
})
} else if (this.status === PromiseStatus.FAIlURE) {
// 如果状态为失败,执行失败回调
queueMicrotask(() => {
try {
const result = errorCallback(this.failureValue);
this.returnValuePromiseManage(newMyPromise, result, resolve, reject);
} catch (e) {
reject(e)
}
})
} else if (this.status === PromiseStatus.LOADING) {
// 如果还未完成 同样加入微队列
this.okCallbackQueue.push(() => {
queueMicrotask(() => {
try {
const result = okCallback(this.value);
this.returnValuePromiseManage(newMyPromise, result, resolve, reject);
} catch (e) {
reject(e)
}
})
});
this.errorCallbackQueue.push(() => {
queueMicrotask(() => {
try {
const result = errorCallback(this.failureValue);
this.returnValuePromiseManage(newMyPromise, result, resolve, reject);
} catch (e) {
reject(e)
}
})
});
}
})
return newMyPromise
}
emm…代码有些冗余,写一个高阶函数优化一下
// 微队列生成器
actuator = (call: Function, reject) => {
return () => {
queueMicrotask(() => {
try {
call();
} catch (e) {
reject(e)
}
})
}
}
then()
then(okCallback: any = (value: any) => value, errorCallback: any = (errorValue: any) => { throw errorValue }) {
if (typeof okCallback !== 'function') {
okCallback = (value: any) => value
}
if (typeof errorCallback !== 'function') {
errorCallback = (errorValue: any) => { throw errorValue }
}
const newMyPromise = new MyPromise((resolve, reject) => {
const okFun = () => {
const result = okCallback(this.value);
this.returnValuePromiseManage(newMyPromise, result, resolve, reject);
}
const errorFun = () => {
const result = errorCallback(this.failureValue);
this.returnValuePromiseManage(newMyPromise, result, resolve, reject);
}
// 如果状态为成功,执行成功回调
if (this.status === PromiseStatus.OK) {
this.actuator(okFun, reject)();
} else if (this.status === PromiseStatus.FAIlURE) {
this.actuator(errorFun, reject)();
} else if (this.status === PromiseStatus.LOADING) {
// 如果还未完成 同样加入微队列
this.okCallbackQueue.push(() => {
queueMicrotask(okFun)
});
this.errorCallbackQueue.push(() => {
queueMicrotask(errorFun)
});
}
})
return newMyPromise
}
在构造函数里也加入一个
try catch
constructor(callback: Function) {
try {
callback(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
💦测试一下
const promise = new MyPromise((resolve, reject) => {
resolve(1)
})
const p2 = promise.then(() => {
return p2
})
p2.then((res) => {
console.log('成功', res)
}, () => {
console.log('失败')
})
运行结果
Chaining cycle detected for promise #<MyPromise>
失败
👀 完美! 这里的
p2
是一个MyPromise
实例,所以会进入returnValuePromiseManage
函数,然后判断p2
和newMyPromise
是否相等,相等就会抛出异常,所以会进入catch
,打印失败
。
然后我们实现
resolve
和reject
的静态方法
static resolve(params: any = void 0) {
if (params instanceof MyPromise) {
return params;
}
return new MyPromise((resolve) => { resolve(params) })
}
static reject(params: any = void 0) {
return new MyPromise((resolve, reject) => {
return reject(params)
})
}
测试一下
const p1 = MyPromise.resolve(1)
const p2 = MyPromise.resolve(p1)
const p3 = MyPromise.reject(1)
const p4 = MyPromise.reject(p3)
p1.then((res) => {
console.log('p1', res)
})
p2.then((res) => {
console.log('p2', res)
})
p3.then((res) => {
console.log('p3', res)
}, (err) => {
console.log('p3', err)
})
p4.then((res) => {
console.log('p4', res)
}, (err) => {
console.log('p4', err)
})
运行结果
p1 1
p2 1
p3 1
p4 MyPromise { status: 2, value: 1, failureValue: undefined, okCallbackQueue: [], errorCallbackQueue: [] }
👀 完美!
到这里,一个简单的
Promise
就实现了,但是还有一些功能没有实现,比如catch
、finally
、all
、race
等等,这些功能都是基于then
实现的,所以我们只需要在then
方法上做一些修改就可以了。
💫全部代码
enum PromiseStatus {
OK = 'fulfilled',
LOADING = 'pending',
FAIlURE = 'rejected'
}
class MyPromise {
// 成功的值
value: any = void 0;
// 当前的状态 默认为等待状态
status = PromiseStatus.LOADING
// 失败的值
failureValue: any = void 0;
// 成功的回调队列
okCallbackQueue: Function[] = [];
// 失败的回调队列
errorCallbackQueue: Function[] = [];
constructor(callback) {
try {
callback(this.resolve, this.reject);
} catch (e) {
this.reject(e)
}
}
resolve = (value: any) => {
if (this.status === PromiseStatus.LOADING) {
this.value = value;
this.status = PromiseStatus.OK;
while (this.okCallbackQueue.length) {
this.okCallbackQueue.shift()!();
}
}
};
reject = (errorValue: any) => {
if (this.status === PromiseStatus.LOADING) {
this.failureValue = errorValue;
this.status = PromiseStatus.FAIlURE;
while (this.errorCallbackQueue.length) {
this.errorCallbackQueue.shift()!();
}
}
};
then(okCallback: any = (value: any) => value, errorCallback: any = (errorValue: any) => { throw errorValue }) {
if (typeof okCallback !== 'function') {
okCallback = (value: any) => value
}
if (typeof errorCallback !== 'function') {
errorCallback = (errorValue: any) => { throw errorValue }
}
const newMyPromise = new MyPromise((resolve, reject) => {
const okFun = () => {
const result = okCallback(this.value);
this.returnValuePromiseManage(newMyPromise, result, resolve, reject);
}
const errorFun = () => {
const result = errorCallback(this.failureValue);
this.returnValuePromiseManage(newMyPromise, result, resolve, reject);
}
// 如果状态为成功,执行成功回调
if (this.status === PromiseStatus.OK) {
this.actuator(okFun, reject)();
} else if (this.status === PromiseStatus.FAIlURE) {
this.actuator(errorFun, reject)();
} else if (this.status === PromiseStatus.LOADING) {
// 如果还未完成 同样加入微队列
this.okCallbackQueue.push(() => {
queueMicrotask(okFun)
});
this.errorCallbackQueue.push(() => {
queueMicrotask(errorFun)
});
}
})
return newMyPromise
}
returnValuePromiseManage(newPromise: MyPromise, result: any, resolve: Function, reject: Function) {
if (newPromise === result) {
const msg = 'Chaining cycle detected for promise #<MyPromise>';
console.error(msg)
reject(new TypeError(msg))
}
if (result instanceof MyPromise) {
// then返回的是一个MyPromise 调用then
result.then(resolve, reject);
} else {
// 不返回或者普通值
resolve(result)
}
}
// 微队列生成器
actuator = (call: Function, reject) => {
return () => {
queueMicrotask(() => {
try {
call();
} catch (e) {
reject(e)
}
})
}
}
static resolve(params: any = void 0) {
if (params instanceof MyPromise) {
return params;
}
return new MyPromise((resolve) => { resolve(params) })
}
static reject(params: any = void 0) {
return new MyPromise((resolve, reject) => {
return reject(params)
})
}
}
四、完结
😵 : 使用js实现的Promise性能自然不及原生,但理解Promise的原理和实现,对于我们更好的使用Promise是很有帮助的。
轻松愉悦的学习冒险,下次见!🍊