一、结构的设计
1.1 创建类
- 接受回调函数(excutor)并执行
class MyPromise {
constructor(executor) {
executor();
}
};
const promise = new MyPromise(() => {
console.log('立即执行')
});
1.2 规定状态
- excutor接受两个回调函数并执行
constructor(executor) { const resolve = (value) => {}; const reject = (reason) => {}; executor(resolve, reject); } const promise = new MyPromise((resolve, reject) => { console.log('立即执行'); resolve(); reject(); });
- 定义状态常量,保留两个回调函数接收的参数
const STATUS_PENDING = 'pending'; const STATUS_FUFILLED = 'fulfilled'; const STATUS_REJECTED = 'rejected'; class MyPromise { constructor(executor) { this.state = STATUS_PENDING; this.value = undefined; this.reason = undefined; const resolve = (value) => { this.value = value; }; const reject = (reason) => { this.reason = reason; }; executor(resolve, reject); } }; const promise = new MyPromise((resolve, reject) => { console.log('立即执行'); resolve('fulfilled'); reject('rejected'); });
- 规定状态,两个回调函数只会执行一个,完整代码
// 2.1.定义状态常量; const STATUS_PENDING = 'pending'; const STATUS_FUFILLED = 'fulfilled'; const STATUS_REJECTED = 'rejected'; class MyPromise { constructor(executor) { this.state = STATUS_PENDING; // 2.2.保留两个回调函数接收的参数; this.value = undefined; this.reason = undefined; // 2.传入两个回调函数并规定状态,二者只执行一个; const resolve = (value) => { if (this.state === STATUS_PENDING) { this.state = STATUS_FUFILLED; this.value = value; console.log('resolve', value); } }; const reject = (reason) => { if (this.state === STATUS_PENDING) { this.state = STATUS_REJECTED; this.reason = reason; console.log('reject', reason); } }; // 1.接收回调函数并执行; executor(resolve, reject); } }; const promise = new MyPromise((resolve, reject) => { console.log('立即执行'); resolve('fulfilled'); reject('rejected'); });
二、then方法设计
- 定义then方法,接受两个回调函数并保留
const STATUS_PENDING = 'pending'; const STATUS_FUFILLED = 'fulfilled'; const STATUS_REJECTED = 'rejected'; class MyPromise { constructor(executor) { this.state = STATUS_PENDING; this.value = undefined; this.reason = undefined; const resolve = (value) => { if (this.state === STATUS_PENDING) { this.state = STATUS_FUFILLED; // 3.1.推入微任务队列调用; queueMicrotask(() => { this.value = value; this.onFufilled(this.value) }); } }; const reject = (reason) => { if (this.state === STATUS_PENDING) { this.state = STATUS_REJECTED; queueMicrotask(() => { this.reason = reason; this.onRejected(this.reason); }); } }; executor(resolve, reject); } // 3.定义then方法,接受两个回调函数并保留; then(onFufilled, onRejected) { this.onFufilled = onFufilled; this.onRejected = onRejected; } }; const promise = new MyPromise((resolve, reject) => { console.log('立即执行'); resolve(111); reject(222); }); promise.then(res => { console.log('res: ', res); }, err => { console.log('err: ', err); });
为什么要使用queueMicrotask这个API呢?
因为当我们调用resolve/reject时,此时还没执行到promise.then的代码,所以当前类并未保留这两个函数,会报错不是一个方法,因此推入到微任务队列中执行。
三、then方法优化一
3.1. 解决定时器里调用then方法
setTimeout(() => {
promise.then(res => {
console.log('res: ', res);
}, err => {
console.log('err: ', err);
})
}, 1000)
当我们这样调用then时,因为定时器是宏任务,所以queueMicrotask里的代码先执行,调用this.onFufilled/this.onRejected会报错。
正确方式应该如下:
const resolve = (value) => {
if (this.state === STATUS_PENDING) {
queueMicrotask(() => {
if (this.state !== STATUS_PENDING) return;
this.state = STATUS_FUFILLED;
this.value = value;
});
}
};
const reject = (reason) => {
if (this.state === STATUS_PENDING) {
queueMicrotask(() => {
if (this.state !== STATUS_PENDING) return;
this.state = STATUS_REJECTED;
this.reason = reason;
});
}
};
then(onFufilled, onRejected) {
// this.onFufilled = onFufilled;
// this.onRejected = onRejected;
if (this.state === STATUS_FUFILLED && onFufilled) {
onFufilled(this.value)
};
if (this.state === STATUS_REJECTED && onRejected) {
onRejected(this.reason)
};
}
3.2. 解决多次调用后者覆盖前者,完整代码
const STATUS_PENDING = 'pending';
const STATUS_FUFILLED = 'fulfilled';
const STATUS_REJECTED = 'rejected';
class MyPromise {
constructor(executor) {
this.state = STATUS_PENDING;
this.value = undefined;
this.reason = undefined;
this.onFufilledFns = [];
this.onRejectedFns = [];
const resolve = (value) => {
if (this.state === STATUS_PENDING) {
queueMicrotask(() => {
if (this.state !== STATUS_PENDING) return;
this.state = STATUS_FUFILLED;
this.value = value;
this.onFufilledFns.forEach(fn => {
fn(this.value)
});
});
}
};
const reject = (reason) => {
if (this.state === STATUS_PENDING) {
queueMicrotask(() => {
if (this.state !== STATUS_PENDING) return;
this.state = STATUS_REJECTED;
this.reason = reason;
this.onRejectedFns.forEach(fn => {
fn(this.reason)
});
});
}
}
executor(resolve, reject);
}
then(onFufilled, onRejected) {
if (this.state === STATUS_FUFILLED && onFufilled) {
onFufilled(this.value)
};
if (this.state === STATUS_REJECTED && onRejected) {
onRejected(this.reason)
};
// 4.解决多次调用then方法被后者覆盖前者;
if (this.state === STATUS_PENDING) {
this.onFufilledFns.push(onFufilled);
this.onRejectedFns.push(onRejected);
}
}
};
const promise = new MyPromise((resolve, reject) => {
resolve(111);
// reject(222);
});
promise.then(res => {
console.log('res: ', res);
}, err => {
console.log('err: ', err);
});
promise.then(res => {
console.log('res2: ', res);
}, err => {
console.log('err2: ', err);
});
setTimeout(() => {
promise.then(res => {
console.log('res3: ', res);
}, err => {
console.log('err3: ', err);
});
}, 1000);
四、then方法优化二
4.1. 解决then的返回值是一个Promise
then(onFufilled, onRejected) {
// 5.解决then的返回值是一个Promise;
return new MyPromise((resolve, reject) => {
if (this.state === STATUS_FUFILLED && onFufilled) {
resolve(onFufilled(this.value));
};
if (this.state === STATUS_REJECTED && onRejected) {
resolve(onRejected(this.reason));
};
if (this.state === STATUS_PENDING) {
this.onFufilledFns.push(() => {
const value = onFufilled(this.value);
resolve(value)
});
this.onRejectedFns.push(() => {
const reason = onRejected(this.reason);
resolve(reason)
});
};
});
}
promise.then(res => {
console.log('res: ', res);
}, err => {
console.log('err: ', err);
}).then(res => {
console.log('res2: ', res);
});
4.2. 解决捕获错误,完整代码
const STATUS_PENDING = 'pending';
const STATUS_FUFILLED = 'fulfilled';
const STATUS_REJECTED = 'rejected';
// 5.3.封装工具函数
function execFnWithCatchErr(execFn, value, resolve, reject) {
try {
const result = execFn(value);
resolve(result);
} catch (err) {
reject(err);
}
};
class MyPromise {
constructor(executor) {
this.state = STATUS_PENDING;
this.value = undefined;
this.reason = undefined;
this.onFufilledFns = [];
this.onRejectedFns = [];
const resolve = (value) => {
if (this.state === STATUS_PENDING) {
queueMicrotask(() => {
if (this.state !== STATUS_PENDING) return;
this.state = STATUS_FUFILLED;
this.value = value;
this.onFufilledFns.forEach(fn => {
fn(this.value)
});
});
}
};
const reject = (reason) => {
if (this.state === STATUS_PENDING) {
queueMicrotask(() => {
if (this.state !== STATUS_PENDING) return;
this.state = STATUS_REJECTED;
this.reason = reason;
this.onRejectedFns.forEach(fn => {
fn(this.reason)
});
});
}
}
// 5.2.捕获executor中的error
try {
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFufilled, onRejected) {
// 5.解决then的返回值是一个Promise;
return new MyPromise((resolve, reject) => {
if (this.state === STATUS_FUFILLED && onFufilled) {
// try {
// const value = onFufilled(this.value);
// resolve(value);
// } catch (err) {
// reject(err);
// }
execFnWithCatchErr(onFufilled, this.value, resolve, reject)
}
if (this.state === STATUS_REJECTED && onRejected) {
// try {
// const reason = onRejected(this.reason);
// resolve(reason);
// } catch (err) {
// reject(err);
// }
execFnWithCatchErr(onRejected, this.reason, resolve, reject)
}
if (this.state === STATUS_PENDING) {
// 5.1.push一个函数;
this.onFufilledFns.push(() => {
// try {
// const value = onFufilled(this.value);
// resolve(value);
// } catch (err) {
// reject(err)
// }
execFnWithCatchErr(onFufilled, this.value, resolve, reject)
});
this.onRejectedFns.push(() => {
// try {
// const reason = onRejected(this.reason);
// resolve(reason);
// } catch (err) {
// reject(err);
// }
execFnWithCatchErr(onRejected, this.reason, resolve, reject)
});
}
})
}
};
const promise = new MyPromise((resolve, reject) => {
// resolve(111);
reject(222);
// throw new Error('executor error')
});
promise.then(res => {
console.log('res: ', res);
return 'aaa';
// throw new Error('a error')
}, err => {
console.log('err: ', err);
return 'bbb';
// throw new Error('b error')
}).then(res => {
console.log('res2: ', res);
}, err => {
console.log('err2: ', err);
});
五、Promise.prototype.catch()
1)
catch()
方法返回一个Promise
,并且处理拒绝的情况;2)它的行为与调用
Promise.prototype.then(undefined, onRejected)
相同;3)事实上
obj.catch(onRejected)
内部调用obj.then(undefined, onRejected)
;
- 定义catch方法,实际上就是调用then方法
// 6.定义catch方法; catch(onRejected) { this.then(undefined, onRejected); }
- 没有调用catch方法时,就抛出到上一个promise里面的第二个函数
then(onFufilled, onRejected) { // 6.1. const defaultOnRejected = err => { throw err }; onRejected = onRejected || defaultOnRejected; return new MyPromise((resolve, reject) => { if (this.state === STATUS_FUFILLED && onFufilled) { execFnWithCatchErr(onFufilled, this.value, resolve, reject) }; if (this.state === STATUS_REJECTED && onRejected) { execFnWithCatchErr(onRejected, this.reason, resolve, reject) }; if (this.state === STATUS_PENDING) { if (onFufilled) this.onFufilledFns.push(() => { execFnWithCatchErr(onFufilled, this.value, resolve, reject) }); if (onRejected) this.onRejectedFns.push(() => { execFnWithCatchErr(onRejected, this.reason, resolve, reject) }); }; }); }
- 结果
const promise = new MyPromise((resolve, reject) => { // resolve(111); reject(222); }); promise.then(res => { console.log('res: ', res); } // , err => { // console.log('err', err); // } ).catch(err => { console.log('catch err', err); });
六、Promise.prototype.finally()
finally()
方法返回一个Promise
。在 promise 结束时,无论结果是 fulfilled 或者是 rejected,都会执行指定的回调函数。
- 定义finally方法
// 7.定义finally方法; finally(onFinally) { this.then(() => { onFinally() }, () => { onFinally() }) }
- catch需要有返回值才能链式调用finally
catch(onRejected) { // 7.1.返回值 return this.then(undefined, onRejected); }
七、完整代码:
const STATUS_PENDING = 'pending';
const STATUS_FUFILLED = 'fulfilled';
const STATUS_REJECTED = 'rejected';
function execFnWithCatchErr(execFn, value, resolve, reject) {
try {
const result = execFn(value);
resolve(result);
} catch (err) {
reject(err);
}
};
class MyPromise {
constructor(executor) {
this.state = STATUS_PENDING;
this.value = undefined;
this.reason = undefined;
this.onFufilledFns = [];
this.onRejectedFns = [];
const resolve = (value) => {
if (this.state === STATUS_PENDING) {
queueMicrotask(() => {
if (this.state !== STATUS_PENDING) return;
this.state = STATUS_FUFILLED;
this.value = value;
this.onFufilledFns.forEach(fn => {
fn(this.value)
});
});
}
};
const reject = (reason) => {
if (this.state === STATUS_PENDING) {
queueMicrotask(() => {
if (this.state !== STATUS_PENDING) return;
this.state = STATUS_REJECTED;
this.reason = reason;
this.onRejectedFns.forEach(fn => {
fn(this.reason)
});
});
}
}
try {
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFufilled, onRejected) {
const defaultOnRejected = err => { throw err };
onRejected = onRejected || defaultOnRejected;
const defaultOnFulfilled = value => { return value };
onFufilled = onFufilled || defaultOnFulfilled;
return new MyPromise((resolve, reject) => {
if (this.state === STATUS_FUFILLED && onFufilled) {
execFnWithCatchErr(onFufilled, this.value, resolve, reject)
};
if (this.state === STATUS_REJECTED && onRejected) {
execFnWithCatchErr(onRejected, this.reason, resolve, reject)
};
if (this.state === STATUS_PENDING) {
if (onFufilled) this.onFufilledFns.push(() => {
execFnWithCatchErr(onFufilled, this.value, resolve, reject)
});
if (onRejected) this.onRejectedFns.push(() => {
execFnWithCatchErr(onRejected, this.reason, resolve, reject)
});
}
});
}
catch(onRejected) {
return this.then(undefined, onRejected);
}
finally(onFinally) {
this.then(() => {
onFinally()
}, () => {
onFinally()
})
}
};
const promise = new MyPromise((resolve, reject) => {
resolve(111);
// reject(222);
});
promise.then(res => {
console.log('res: ', res);
return 'dsadsad'
}
// , err => {
// console.log('err', err);
// }
)
.then(res => {
console.log('res2: ', res);
})
.catch(err => {
console.log('err', err);
}).finally(() => {
console.log('finally');
})