核心概念
实现自己的Promise的重点pedding时缓存回调,变更后异步触发
关键原理
下面是自己实现的Promise
js
class MyPromise {
constructor(executor) {
this.state = 'pending';
this.value = null;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
if (this.state !== 'pending') return;
this.state = 'fulfilled';
this.value = value;
this.onFulfilledCallbacks.forEach(fn => fn());
};
const reject = (reason) => {
if (this.state !== 'pending') return;
this.state = 'rejected';
this.value = reason;
this.onRejectedCallbacks.forEach(fn => fn());
};
try {
executor(resolve, reject); // 同步执行 executor
} catch (e) {
reject(e);
}
}
then(onFulfilled, onRejected) {
if (this.state === 'fulfilled') {
onFulfilled(this.value);
} else if (this.state === 'rejected') {
onRejected(this.value);
} else { // pending 状态保存回调
this.onFulfilledCallbacks.push(() => onFulfilled(this.value));
this.onRejectedCallbacks.push(() => onRejected(this.value));
}
}
}
然后是调用的例子
js
let aPromise = new MyPromise(reslove => {
setTimeout(() => {
reslove('123')
}, 5000)
})
如果我们在5秒内输出aPromise
,得到的结果是
js
{
onFulfilledCallbacks: []
onRejectedCallbacks: []
state: "pedding"
value: null
}
MyPromise
这个类的作用就是初始化五秒钟内输出的这样一个对象,这个时候,Mypromise
内的参数是同步执行的,但是一个定时器,让我们在五秒钟后才会触发类中的reslove
方法,这个时候才会把status
改为fulfilled
,value
改为3
,所以我们五秒后如果在输出aPromise
,会得到结果
js
{
onFulfilledCallbacks: []
onRejectedCallbacks: []
state: "fulfilled"
value: '123'
}
别忘了,我们的MyPromise
类中还有一个then
的方法,顺着输出的原型链,我们可以看到then
的输出,上面代码的实现中我们只是实现了一层的then
的方法,真正的promise
需要我们在then
同样返回一个promise,不过我们先来看看这个简单的实现。 和MyPromise
的构造函数类似,在then
中,我们传递两个回调函数,并在pedding的时候保存这两个函数,这两个函数的作用就是在state == fulfilled
时候调用第一个,也就是成功的回调,当state == reject
时候调用第二个,也就是异常的回调。 当然真实的Promise不是这样简单,我们还是要看看如何实现链式调用。
js
then(onFulfilled, onRejected) {
// 1. 参数标准化(处理值穿透)
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v;
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
// 2. 创建新Promise(链式调用基础)
const promise2 = new MyPromise((resolve, reject) => {
const handleCallback = (callback) => {
setTimeout(() => { // 异步执行(微任务模拟)
try {
const x = callback(this.value);
resolvePromise(promise2, x, resolve, reject); // 关键!
} catch (e) {
reject(e);
}
}, 0);
};
// 3. 状态分派逻辑
if (this.state === 'fulfilled') handleCallback(onFulfilled);
else if (this.state === 'rejected') handleCallback(onRejected);
else { // pending状态时存入队列
this.onFulfilledCallbacks.push(() => handleCallback(onFulfilled));
this.onRejectedCallbacks.push(() => handleCallback(onRejected));
}
});
return promise2; // 返回新Promise实现链式
}
链式调用的基础就是在then
中返回一个新的Promise
,所以我们肯定首先需要的是先创建一个promise
用于返回,下面根据state
的状态来进行暂存或者调用回调函数是和之前类似的,只是这里我们没有直接去触发回调函数,因为回调函数中从来不是简单的几行赋值,打印的代码,它是有可能包含同样是Promise
的代码的,所以then中不但要返回一个新的Promise,还有把可能包含在回调函数中的Promise解析出来,这就是resolvePromise
的作用
js
function resolvePromise(promise2, x, resolve, reject) {
// 1. 循环引用检测(Promise/A+ 2.3.1)
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected'));
}
// 2. 对象/函数类型处理
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
let called = false; // 防止多次调用
try {
const then = x.then;
if (typeof then === 'function') { // 识别为Promise
then.call(
x,
y => { // 递归解析
if (called) return;
called = true;
resolvePromise(promise2, y, resolve, reject);
},
r => { // 直接拒绝
if (called) return;
called = true;
reject(r);
}
);
} else { // 普通对象
resolve(x);
}
} catch (e) {
if (called) return;
reject(e);
}
} else { // 基本类型直接resolve
resolve(x);
}
}
递归调用,为Promise
resolve
出最终的结果。 结合下面对应的流程图更好理解
另外
代码中还有一些类型的判断是必须要有的,但是没有去解释,因为这里的重点只是去梳理整个流程,从宏观上掌握实现逻辑