Hi! 这里是JustHappy ,既然点开了这个JS硬气功,那就一起愉快的修炼吧!我想大家和我一样,在面试中遇到Primise手写题 这类的总是想不起来,所以这次我们尝试使用JS硬气功暴打一下,话不多说,我们开始吧。
这篇我们再续上文,去实现一下Promise的 .then()/.catch()(包含链式调用)
我们的构造函数
我们在上篇所写的构造函数如下,我们将在这个基础上进行改进
如果需要看之前的实现逻辑,可以点这里「JS硬气功👊」Promise异步移形换影------上(我们一起暴打Promise手写题)
js
class MyPromise {
state = "pending";
value = undefined;
reason = undefined;
resolveCallbacks = [];
rejectCallbacks = [];
constructor(fn) {
const resolveHandler = (value) => {
if (this.state === "pending") {
this.state = "fulfilled";
this.value = value;
// 遍历执行成功的回调
this.resolveCallbacks.forEach((fn) => fn(this.value));
}
};
const rejectHandler = (reason) => {
if (this.state === "pending") {
this.state = "rejected";
this.reason = reason;
// 遍历执行失败的回调
this.rejectCallbacks.forEach((fn) => fn(this.reason));
}
};
try {
fn(resolveHandler, rejectHandler);
} catch {
rejectHandler();
}
}
// 这边以下是then
then(fn1, fn2) {}
}
链式调用的实现
链式调用无非就是完善我们的 .then() 和 .catch() 方法,如果你对 .catch 方法比较熟悉,你会发现 .catch 方法实际上就是 .then 的一个语法糖,一个只返回错误的 .then,于是乎我们可以这样写
js
class MyPromise {
state = "pending";
value = undefined;
reason = undefined;
resolveCallbacks = [];
rejectCallbacks = [];
constructor(fn) {
......
}
// 这边以下是then
then(fn1, fn2) {}
catch(fn){
return this.then(null, fn)
}
}
可以看到我们在 .catch 方法中给 .then 传入了 null,所以我们需要在 .then 方法中添加判断,这里我们使用三元实现
js
class MyPromise {
state = "pending";
value = undefined;
reason = undefined;
resolveCallbacks = [];
rejectCallbacks = [];
constructor(fn) {
......
}
// 这边以下是then
then(fn1, fn2) {
fn1 = typeof fn1 === 'function' ? fn1 : (v) => v //不为function的时候参数直接返回
fn2 = typeof fn2 === 'function' ? fn2 : (e) => e //不为function的时候参数直接返回
}
catch(fn){
return this.then(null, fn)
}
}
深入.then
我们回忆一下上篇, .then() 中要做什么呢?是的,如果在pending状态下,应该把传入的函数放到resolveCallbacks 和 rejectCallbacks 中,其他状态下只要执行对应的函数和传递参数就行了,但是都是返回一个新的Promise对象,那么就会像下面这样
js
class MyPromise {
state = 'pending';
value = undefined;
reason = undefined;
resolveCallbacks = [];
rejectCallbacks = [];
constructor(fn) {
......
}
// 这边以下是then
then(fn1, fn2) {
fn1 = typeof fn1 === 'function' ? fn1 : (v) => v
fn2 = typeof fn2 === 'function' ? fn2 : (e) => e
if(this.state === 'pending'){
const p = new MyPromise((resolve, reject) => {})
return p
}
if(this.state === 'fulfilled'){
const p = new MyPromise((resolve, reject) => {})
return p
}
if(this.state === 'rejected'){
const p = new MyPromise((resolve, reject) => {})
return p
}
}
catch(fn){
return this.then(null, fn)
}
}
fulfilled 和 rejected 的状态下相对来说比较好写,我们先来实现一下,很简单,就是执行对应的函数和传递参数,不过我们需要加个 try / catch 去验证一下传入的函数是否ok,那么就会是下面这样
js
class MyPromise {
state = 'pending';
value = undefined;
reason = undefined;
resolveCallbacks = [];
rejectCallbacks = [];
constructor(fn) {
......
}
// 这边以下是then
then(fn1, fn2) {
fn1 = typeof fn1 === 'function' ? fn1 : (v) => v
fn2 = typeof fn2 === 'function' ? fn2 : (e) => e
if(this.state === 'pending'){
const p = new MyPromise((resolve, reject) => {})
return p
}
if(this.state === 'fulfilled'){ // 执行函数fn1 传递参数 value
const p = new MyPromise((resolve, reject) => {
try{
const newValue = fn1(this.value) // MyPromise的value
resolve(newValue)
}catch(err){
reject(err)
}
})
return p
}
if(this.state === 'rejected'){ // 执行函数fn2 传递错误原因 reason
const p = new MyPromise((resolve, reject) => {
try{
const newReason = fn2(this.reason) // MyPromise的value
reject(reason)
}catch(err){
reject(err)
}
})
return p
}
}
catch(fn){
return this.then(null, fn)
}
}
ok,我们现在来处理pending 状态下的情况,也就是我们在未知之后状态的情况下我们需要存储任务,就是将传入的fn1、fn2存到resolveCallbacks 和rejectCallbacks,同样,我们不知道fn1、fn2是否是ok的,所以我们也需要使用try / catch去测试一下
js
class MyPromise {
state = 'pending';
value = undefined;
reason = undefined;
resolveCallbacks = [];
rejectCallbacks = [];
constructor(fn) {
......
}
// 这边以下是then
then(fn1, fn2) {
fn1 = typeof fn1 === 'function' ? fn1 : (v) => v
fn2 = typeof fn2 === 'function' ? fn2 : (e) => e
if(this.state === 'pending'){
// 注意,这里只是存储函数,并没有在这里执行
const p = new MyPromise((resolve, reject) => {
this.resolveCallbacks.push(() => {
try{
const newValue = fn1(this.value)
resolve(newValue)
}catch(err){
reject(err)
}
})
this.rejectCallbacks.push(() => {
try{
const newReason = fn2(this.reason)
reject(newReason)
}catch(err){
reject(err)
}
})
})
return p
}
if(this.state === 'fulfilled'){
......
}
if(this.state === 'rejected'){
......
}
}
catch(fn){
return this.then(null, fn)
}
}
ok,目前链式调用部分基本完成了,目前完整的代码如下
js
class MyPromise {
state = "pending";
value = undefined;
reason = undefined;
resolveCallbacks = [];
rejectCallbacks = [];
constructor(fn) {
const resolveHandler = (value) => {
if (this.state === "pending") {
this.state = "fulfilled";
this.value = value;
// 遍历执行成功的回调
this.resolveCallbacks.forEach((fn) => fn(this.value));
}
};
const rejectHandler = (reason) => {
if (this.state === "pending") {
this.state = "rejected";
this.reason = reason;
// 遍历执行失败的回调
this.rejectCallbacks.forEach((fn) => fn(this.reason));
}
};
try {
fn(resolveHandler, rejectHandler);
} catch {
rejectHandler();
}
}
// 这边以下是then
then(fn1, fn2) {
fn1 = typeof fn1 === "function" ? fn1 : (v) => v;
fn2 = typeof fn2 === "function" ? fn2 : (e) => e;
if (this.state === "pending") {
const p = new MyPromise((resolve, reject) => {
this.resolveCallbacks.push(() => {
try {
const newValue = fn1(this.value);
resolve(newValue);
} catch (err) {
reject(err);
}
});
this.rejectCallbacks.push(() => {
try {
const newReason = fn2(this.reason);
reject(newReason);
} catch (err) {
reject(err);
}
});
});
return p;
}
if (this.state === "fulfilled") {
// 执行函数fn1 传递参数 value
const p = new MyPromise((resolve, reject) => {
try {
const newValue = fn1(this.value); // MyPromise的value
resolve(newValue);
} catch (err) {
reject(err);
}
});
return p;
}
if (this.state === "rejected") {
// 执行函数fn2 传递错误原因 reason
const p = new MyPromise((resolve, reject) => {
try {
const newReason = fn2(this.reason); // MyPromise的value
reject(newReason);
} catch (err) {
reject(err);
}
});
return p;
}
}
catch(fn) {
return this.then(null, fn);
}
}
我们来测试一下吧!
这里的执行结果如下
如果是reject,就是下面这样
结果是下面这样
ok,我们链式调用的实现就到这里了,下篇我们继续完善我们的MyPromise