最近看到好多讲解Promise源码解析,或者自己实现一个Promise的文章,突然想自己造个轮子试一试。
先说明一下,该轮子并不完全遵守任何标准和规范,只是对标准Promise使用后的理解和感受而编写的,纯属兴趣研究。
下面是实现代码:
// 对象类型判断
const is = (typeAsString) => obj => Object.prototype.toString.call(obj) === typeAsString
// 判断是否为一个Error对象
const isError = is('[object Error]')
/**
* 自定义Promise对象
* @param {(resolve: (value: any) => void, reject: (reason: any) => void) => void} executor
*/
function MyPromise(executor) {
this.executor = executor
// 初始状态为pending...
this.status = 'pending'
/**
* 内部判定状态,只有处于pending状态才可继续执行
* @param {number} value
*/
function resolve(value) {
if (this.status === 'pending') { // 确保只执行一次
this.onfulfilled = ___onfulfilled.call(this, value)
}
}
/**
* 为了缓存resolve方法的执行结果
* @param {*} value value就是resolve方法的执行结果
*/
function ___onfulfilled(value) {
this.status = 'fulfilled' // 更改内部状态
/**
* @param {(value: number) => void} onfulfilled 这里是then方法中传入的参数
*/
return (onfulfilled) => {
return onfulfilled(value) //
}
}
/**
* 触发异常的方法
* @param {string} reason
*/
function reject(reason) {
if (this.status === 'pending') { // 确保只执行一次
this.onrejected = ___onrejected.call(this, reason)
}
}
/**
*
* @param {Error} reason 如果传入的不是一个Error对象,那么会使用Error包装一下
*/
function ___onrejected(reason) {
this.status = 'rejected' // 更改内部状态
return (onrejected) => {
reason = isError(reason) ? reason : new Error(reason)
return onrejected(reason)
}
}
/**
* @param {(value: number) => any} onfulfilled 处理成功的函数
* @param {(reason: any) => void} onrejected 处理出现异常的函数,如果传入该参数,那么catch方法就捕获不到了
*/
this.then = function(onfulfilled, onrejected) {
const self = this
return new MyPromise((resolve, reject) => {
setTimeout(function waitStatus() {
switch (self.status){
case 'fulfilled': // resolved
if (onfulfilled) {
// 将onfulfilled方法的返回值交给resolve,确保下一个.then方法能够得到上一个.then方法的返回值
const nextValue = self.onfulfilled(onfulfilled)
resolve(nextValue)
} else {
resolve() // 没有传入参数,假装传入了参数:)
}
break
case 'rejected': // rejected
if (!onrejected) { // 如果没有传递onrejected参数,默认实现一个,确保catch方法能够捕获到
onrejected = (reason) => reason
}
const nextReject = self.onrejected(onrejected)
reject(nextReject)
break
case 'pending': //
default:
setTimeout(waitStatus, 0) // 只要是pending状态,继续等待,直到不是pending
break
}
}, 0);
})
}
/**
* 捕获异常
* @param {(reason: any) => void} onrejected
*/
this.catch = function(onrejected) {
const self = this
setTimeout(function reject() {
if (self.status === 'rejected') {
self.onrejected(onrejected)
} else {
setTimeout(reject, 0);
}
}, 0);
}
// 直接执行
this.executor(resolve.bind(this), reject.bind(this));
}
目前不考虑参数传入的正确性,假设传入的参数全部是正确的情况下,在nodejs环境下能够正常运行。以下是测试代码:
// 覆盖nodejs环境中的标准Promise对象
global.Promise = MyPromise
async function test () {
const r = await new Promise((resolve) => {
setTimeout(() => {
resolve(121)
}, 1000);
})
console.log(r) // 打印121
}
test()
以上代码主要是使用setTimeout方法去检查Promise对象内部的状态,一旦发生变化立即作出相应的处理。
因为是靠setTimeout方法检查Promise内部的状态,所以属于宏指令任务,执行的优先级不像标准Promise那么高。
setTimeout(() => {
console.log(1)
}, 0);
new MyPromise((resolve, reject) => {
console.log(2)
resolve(3)
}).then(v => {
console.log(v)
})
上面代码的输出是2,1,3
标准Promise的输出结果应该是2,3,1
源代码在此。谢谢观看!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。