正常使用的 promise:
const lcPromise = new LcPromise((resolve, reject) => {
resolve("resolve1");
reject("reject1");
})
lcPromise.then(
(res) => {
console.log("res1: ", res);
},
(err) => {
console.log("err1: ", err);
}
);
lcPromise.then(
(res) => {
console.log("res2: ", res);
},
(err) => {
console.log("err2: ", err);
}
);
// 输出
// resolve1
// res1: resolve1
// res2: resolve1
基本结构
由上观察可知:
- Promsie 构造函数肯定接收一个参数函数
- 参数函数接收两个函数作为参数(resolve,reject)
- promise 拥有一个实例方法 then
- then 方法也接收两个参数函数(onFulfilled,onRejected)
- 根据Promise/A+ 规范,promise 有三种状态
- 规范规定,只有为 pending 状态,才能执行 resolve,reject,并且执行完更改对应状态
const PROMISE_STATUS_PENDING = "pending";
const PROMISE_STATUS_FULFILLED = "fulfilled";
const PROMISE_STATUS_REJECTED = "rejected";
class LcPromise {
constructor(executed) {
this.status = PROMISE_STATUS_PENDING;
const resolve = value => {
if (this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_FULFILLED
}
}
const reject = reason => {
if (this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_REJECTED
}
}
executed(resolve, reject)
}
then(onFulfilled, onRejected) {
}
}
then 方法
我们知道执行 resolve 后就会执行 then 中的第一个参数函数,所以 then 中的参数函数调用肯定是在 resolve 函数的函数体中,这样才能做到 resolve 函数执行,然后 then 的参数函数跟着执行。
并且 then 可以多次调用,接收的多个参数函数可以依次执行,所以 then 接收的参数函数肯定被收集起来了。
并且每个 then 的参数函数都能接收到 resolve 或者 reject 中的实参。
class LcPromise {
constructor(executed) {
this.status = PROMISE_STATUS_PENDING;
// 收集 then 的参数
this.onFulfilledFns = []
this.onRejectedFns = []
const resolve = value => {
if (this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_FULFILLED
// 执行 then 中函数
this.onFulfilledFns.forEach((fn) => fn(value));
}
}
const reject = reason => {
if (this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_REJECTED
this.onRejectedFns.forEach((fn) => fn(reason));
}
}
executed(resolve, reject)
}
then(onFulfilled, onRejected) {
this.onFulfilledFns.push(onFulfilled)
this.onRejectedFns.push(onRejected)
}
}
上述代码执行,会发现 resolve 执行时,onFulfilledFns 数组中并没有添加 then 中的参数函数,为什么?
因为 new 只会执行 constructor 方法,还没执行到 then 方法,resolve 方法就执行完了,自然就收集不到 then 的参数函数了。
所以现在目标是要让 then 方法先执行完毕,才去执行 resolve 中对 then 参数函数的调用。
可以使用事件循环,resolve 和 then是同步任务,将 resolve 中调用 then 参数函数的部分加入微任务队列,这样就能在 then 执行完收集后,再去调用了。
const resolve = value => {
if (this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_FULFILLED
// 加入微任务队列
queueMicrotask(() => {
// 执行 then 中函数
this.onFulfilledFns.forEach((fn) => fn(value));
})
}
}
const reject = reason => {
if (this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_REJECTED
queueMicrotask(() =>{
this.onRejectedFns.forEach((fn) => fn(reason));
})
}
}
resolve 中 then 参数函数的调用加入了微队列,延迟在同步任务之后执行,解决了收集的问题。现在假如 then 函数本身在宏任务中呢?微任务先于宏任务,那宏任务中的 then 方法的参数就收集不到了。
// 宏任务中调用 then,resolve 无法收集到 then 的参数函数
setTimeout(() => {
lcPromise.then(
(res) => {
console.log("res3: ", res);
},
(err) => {
console.log("err3: ", err);
}
);
})
因此,宏任务中的 then 参数函数不能放在 resolve 中执行了。因为此时 resolve 已经执行完,所以在 resolve 执行完后的 then 参数都要在 then 中自己执行。
resolve 执行完,promise 状态变成了 fulfilled,所以在 fulfilled 后收集的参数都要自己执行。
并且参数函数需要拿到 resolve 的实参,之前参数函数在 resolve 中执行,可以拿到实参,现在参数函数在 resolve 外部执行,拿不到了,所以需要将实参保存到 promise 实例中共享。
class LcPromise {
constructor(executed) {
this.status = PROMISE_STATUS_PENDING;
this.onFulfilledFns = []
this.onRejectedFns = []
this.value = undefined
this.reason = undefined
const resolve = value => {
if (this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_FULFILLED
this.value = value
queueMicrotask(() => {
this.onFulfilledFns.forEach((fn) => fn(value));
})
}
}
const reject = reason => {
if (this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_REJECTED
this.reason = reason
queueMicrotask(() =>{
this.onRejectedFns.forEach((fn) => fn(reason));
})
}
}
executed(resolve, reject)
}
then(onFulfilled, onRejected) {
// 1. 在 resolve 中执行
this.onFulfilledFns.push(onFulfilled)
this.onRejectedFns.push(onRejected)
// 2. fulfilled 状态后收集的参数函数,在自身中执行
if (this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
onFulfilled(this.value)
}
if (this.status === PROMISE_STATUS_REJECTED && onRejected) {
onRejected(this.reason)
}
}
}
现在存在一个问题,先来看下测试代码的执行过程:
const lcPromise = new LcPromise((resolve, reject) => {
resolve("resolve1");
reject("reject1");
})
lcPromise.then(
(res) => {
console.log("res1: ", res);
},
(err) => {
console.log("err1: ", err);
}
);
setTimeout(() => {
lcPromise.then(
(res) => {
console.log("res3: ", res);
},
(err) => {
console.log("err3: ", err);
}
);
})
// 结果:res1 执行了两遍
// res1: resolve1
// res1: resolve1
// res3: resolve1
- new 构造函数,constructor 执行,参数函数 executed 开始执行,然后执行 resolve。
- 执行 resolve 的时候,判断是 pending 后立刻将状态改成了 fulfilled,然后将剩下部分加入微任务队列。
- 然后执行 reject,pending 判断不通过,跳出,constructor 同步任务执行完毕,开始执行实例方法 then。
- 第一个 then 调用开始执行,then 中将 res1、err1 加入收集数组,然后判断 promise 为 fulfilled,然后立即执行参数函数 res1、err1。问题就出在这里。
第一个then是同步任务调用,它的参数函数已经加入数组在 resolve 中等待微任务执行,可是现在在同步任务中立即执行了。它就执行了两遍。问题就出在 promise 的状态变早了,promise 的状态不能在同步任务中变成 fulfilled,因为 then 肯定是在 resolve 之后执行。promise 应该在微任务队列中改变状态,这样同步任务的 then 判断始终是 pending,就不会立即执行了。
const resolve = value => {
if (this.status === PROMISE_STATUS_PENDING) {
this.value = value
queueMicrotask(() => {
// 保持同步任务中,promise 状态为 pending
this.status = PROMISE_STATUS_FULFILLED
this.onFulfilledFns.forEach((fn) => fn(value));
})
}
}
const reject = reason => {
if (this.status === PROMISE_STATUS_PENDING) {
this.reason = reason
queueMicrotask(() =>{
this.status = PROMISE_STATUS_REJECTED
this.onRejectedFns.forEach((fn) => fn(reason));
})
}
}
// 结果:then 中成功和失败的参数函数都执行了
// res1: resolve1
// err1: reject1
// err3: reject1
但是这样还有一个问题:resolve 和 reject 都是同步任务,如果它们中的状态改变在微任务中,那就互相锁不住了。比如先执行 resolve ,将部分代码加入微任务队列后跳出,继续执行 reject,按理此时 reject 不应该执行有效代码,但是此时 promise 状态依然为 pending,没有锁住 reject,reject 正常执行,将其中的代码也加入了微任务队列。到时候就会看到 then 中的 res 参数函数和 err 参数函数都执行了。
因此,我们需要在微任务队列中通过判断 promise 的状态来互相阻止 resolve 和 reject 中的有效代码执行。
const resolve = value => {
this.value = value
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING) return
this.status = PROMISE_STATUS_FULFILLED
this.onFulfilledFns.forEach((fn) => fn(value));
})
}
const reject = reason => {
this.reason = reason
queueMicrotask(() =>{
if (this.status !== PROMISE_STATUS_PENDING) return
this.status = PROMISE_STATUS_REJECTED
this.onRejectedFns.forEach((fn) => fn(reason));
})
}
链式调用
const lcPromise = new LcPromise((resolve, reject) => {
resolve("resolve1");
reject("reject1");
})
.then(
(res) => {
console.log("res1: ", res);
},
(err) => {
console.log("err1: ", err);
}
)
.then(
(res) => {
console.log("res2: ", res);
},
(err) => {
console.log("err2: ", err);
}
);
为什么 then 可以链式调用?
因为 then 本身返回了一个 promise。所以我们也要在 then 中返回一个 promise。
then(onFulfilled, onRejected) {
// 1. 在 resolve 中执行
this.onFulfilledFns.push(onFulfilled);
this.onRejectedFns.push(onRejected);
// 2. fulfilled 状态后收集的参数函数,在自身中执行
if (this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
onFulfilled(this.value);
}
if (this.status === PROMISE_STATUS_REJECTED && onRejected) {
onRejected(this.reason);
}
return new LcPromise((resolve, reject) => {
resolve("the second promise")
})
}
现在 then 已经返回一个新的 promise 可以进行链式调用了,但是新 promise 中 resolve 的实参不应该是个定值。正常来讲,新 promise 中的 resolve 应该接收第一个 promise 中 then onFulfilled 参数函数的返回值。
为了让 resolve 拿到上一个 then 参数函数的返回值,可以把之前 then 中的代码全加入到第二个 promise 中,因为 constructor 都是同步执行,所以和在外部没啥区别。
then(onFulfilled, onRejected) {
return new LcPromise((resolve, reject) => {
// 1. 在 resolve 中执行
this.onFulfilledFns.push(onFulfilled);
this.onRejectedFns.push(onRejected);
// 2. fulfilled 状态后收集的参数函数,在自身中执行
if (this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
const value = onFulfilled(this.value);
// resolve("the second promise")
resolve(res)
}
if (this.status === PROMISE_STATUS_REJECTED && onRejected) {
const reason = onRejected(this.reason);
reject(reason)
}
})
}
上述代码有个严重的问题。正常情况下,前一个 then 中参数函数的返回值,无论是参数函数 onFulfilled 还是 onRejected 的返回值,它们都是被传入下一个 then 的 onFulfilled 中作为实参,也就是下一个 promise 中的 resolve 中作为实参。而不是 onFulfilled 与 resolve 对应,onRejected 与 reject 对应。只有上一个 then 中参数函数抛出的错误,才会传给下一个 promise 的 reject,也就是下一个 then 的 onRejected。
所以上述代码的 onRejected 中,不应该是 reject(reason),应该是 resolve(reason)。并且 onFulfilled 和 onRejected 都要被 try…catch 包裹,以将错误信息传给下一个 then 的 onRejected 中。
then(onFulfilled, onRejected) {
return new LcPromise((resolve, reject) => {
// 1. 在 resolve 中执行
this.onFulfilledFns.push(onFulfilled);
this.onRejectedFns.push(onRejected);
// 2. fulfilled 状态后收集的参数函数,在自身中执行
if (this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
try {
const value = onFulfilled(this.value);
resolve(value);
} catch (error) {
reject(error);
}
}
if (this.status === PROMISE_STATUS_REJECTED && onRejected) {
try {
const reason = onRejected(this.reason);
resolve(reason);
} catch (error) {
reject(error);
}
}
});
}
现在对那些在 then 自身中调用的参数函数已经处理好了,第二个 promise 的 resolve 很容易拿到它们的返回值,但那些被加入到数组中在第一个 promise 的 resolve 中执行的参数函数的返回值怎么办?
第一种办法是可以将它们的返回值保存出来共享,就像这样:
const resolve = (value) => {
this.value = value
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING) return;
this.status = PROMISE_STATUS_FULFILLED;
this.firstPromiseValue = this.onFulfilledFns.forEach((fn) => fn(value));
});
};
const reject = (reason) => {
this.reason = reason;
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING) return;
this.status = PROMISE_STATUS_REJECTED;
this.firstPromiseReason = this.onRejectedFns.forEach((fn) => fn(reason));
});
};
虽然可以,但是管理起来变量起来很麻烦。还有一个更巧妙的方式,不再直接将 then 的参数函数直接添加进数组中,而是将参数函数包裹一层函数后添加到数组中,然后在包裹函数的函数体中执行参数函数。这样相当于把参数函数的执行也留在了 then 自身中,添加到收集数组中的只是一个引线,resolve 中启动这根引线,开始执行参数函数。
// 1. 在 resolve 中执行
// this.onFulfilledFns.push(onFulfilled);
// this.onRejectedFns.push(onRejected);
this.onFulfilledFns.push(() => {
try {
const value = onFulfilled();
resolve(value);
} catch (error) {
reject(error);
}
});
this.onRejectedFns.push(() => {
try {
const reason = onRejected();
resolve(reason);
} catch (error) {
reject(error);
}
});
基本实现
const PROMISE_STATUS_PENDING = "pending";
const PROMISE_STATUS_FULFILLED = "fulfilled";
const PROMISE_STATUS_REJECTED = "rejected";
class LcPromise {
constructor(executed) {
this.status = PROMISE_STATUS_PENDING;
// 收集 then 的参数
this.onFulfilledFns = [];
this.onRejectedFns = [];
this.value = undefined;
this.reason = undefined;
const resolve = (value) => {
this.value = value;
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING) return;
this.status = PROMISE_STATUS_FULFILLED;
this.onFulfilledFns.forEach((fn) => fn(value));
});
};
const reject = (reason) => {
this.reason = reason;
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING) return;
this.status = PROMISE_STATUS_REJECTED;
this.onRejectedFns.forEach((fn) =>
fn(reason)
);
});
};
executed(resolve, reject);
}
then(onFulfilled, onRejected) {
return new LcPromise((resolve, reject) => {
// 1. 在 resolve 中执行
if (onFulfilled) this.onFulfilledFns.push(() => {
try {
const value = onFulfilled(this.value);
resolve(value);
} catch (error) {
reject(error);
}
});
if (onRejected) this.onRejectedFns.push(() => {
try {
const reason = onRejected(this.reason);
resolve(reason);
} catch (error) {
reject(error);
}
});
// 2. fulfilled 状态后收集的参数函数,在自身中执行
if (this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
try {
const value = onFulfilled(this.value);
resolve(value);
} catch (error) {
reject(error);
}
}
if (this.status === PROMISE_STATUS_REJECTED && onRejected) {
try {
const reason = onRejected(this.reason);
resolve(reason);
} catch (error) {
reject(error);
}
}
});
}
}
测试:第二个 then 的 onFulfilled
const lcPromise = new LcPromise((resolve, reject) => {
resolve("resolve1")
reject("reject1")
})
.then(
(res) => {
console.log("res1: ", res);
return "aaa";
},
(err) => {
console.log("err1: ", err);
return "bbb"
}
)
.then(
(res) => {
console.log("res2: ", res);
},
(err) => {
console.log("err2: ", err);
}
);
// 结果
res1: resolve1
res2: aaa
// 结果2(注释 resolve("resolve1"),走第一个 then 的 onRejected)
err1: reject1
res2: bbb
测试:第二个 then 的 onRejected
const lcPromise = new LcPromise((resolve, reject) => {
resolve("resolve1");
reject("reject1");
})
.then(
(res) => {
console.log("res1: ", res);
throw 'hhh'
return "aaa";
},
(err) => {
console.log("err1: ", err);
throw "ikun"
return "bbb";
}
)
.then(
(res) => {
console.log("res2: ", res);
},
(err) => {
console.log("err2: ", err);
}
);
// 结果
res1: resolve1
err2: hhh
// 结果2 (注释 resolve("resolve1"),走第一个 then 的 onRejected)
err1: reject1
err2: ikun
上面重复的代码过多,可以抽取封装一下。
const execFunctionWithCatchError = (execFn, value, resolve, reject) => {
try {
const res = execFn(value)
resolve(res)
} catch (error) {
reject(error)
}
}
const PROMISE_STATUS_PENDING = "pending";
const PROMISE_STATUS_FULFILLED = "fulfilled";
const PROMISE_STATUS_REJECTED = "rejected";
const execFunctionWithCatchError = (execFn, value, resolve, reject) => {
try {
const res = execFn(value);
resolve(res);
} catch (error) {
reject(error);
}
};
class LcPromise {
constructor(executed) {
this.status = PROMISE_STATUS_PENDING;
// 收集 then 的参数
this.onFulfilledFns = [];
this.onRejectedFns = [];
this.value = undefined;
this.reason = undefined;
const resolve = (value) => {
this.value = value;
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING) return;
this.status = PROMISE_STATUS_FULFILLED;
this.onFulfilledFns.forEach((fn) => fn(this.value));
});
};
const reject = (reason) => {
this.reason = reason;
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING) return;
this.status = PROMISE_STATUS_REJECTED;
this.onRejectedFns.forEach((fn) => fn(this.reason));
});
};
executed(resolve, reject);
}
then(onFulfilled, onRejected) {
return new LcPromise((resolve, reject) => {
// 1. 在 resolve 中执行
if (onFulfilled) this.onFulfilledFns.push(() => {
execFunctionWithCatchError(onFulfilled, this.value, resolve, reject);
});
if (onRejected) this.onRejectedFns.push(() => {
execFunctionWithCatchError(onRejected, this.reason, resolve, reject);
});
// 2. fulfilled 状态后收集的参数函数,在自身中执行
if (this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
execFunctionWithCatchError(onFulfilled, this.value, resolve, reject);
}
if (this.status === PROMISE_STATUS_REJECTED && onRejected) {
execFunctionWithCatchError(onRejected, this.reason, resolve, reject);
}
});
}
}
catch 方法
catch 方法并不是规范中的,只是 ES6 便于大家使用自己加的。
本来处理 promise 的 reject 是在 then 的第二个参数函数中,现在放在 then 链式调用的 catch 中。那我们可以手动将 then 拆成两部分执行。
catch(onRejected) {
this.then(undefined, onRejected)
}
const lcPromise = new LcPromise((resolve, reject) => {
reject("reject1");
})
.then((res) => {
console.log("res1: ", res);
}, undefined)
.catch((err) => {
console.log("catch: ", err);
});
但是上面这样其实是有问题的,
本来,reject 我们想要调用的是第一个 promise 的 onRejected 回调函数,但是因为 then 中第二个参数为 undefined,所以第一个 promise 的收集数组中是空的。现在用 catch 接收 onRejected 回调。
但是 catch 是链式调用的,真正调用 catch 的是第一个 then 返回的新 promise 实例。也就是 catch 中接收的 onRejected 实参函数被加到第二个 promise 的 onRejectedFns 数组中了。
那通过第一个 promise 的 reject 怎么执行到第二个 promise 的 onRejected 回调呢?
第一种办法,肯定是将这个回调重新加到第一个 promise 的 onRejectedFns 数组中,这样行,但是非常麻烦。
第二种方法,不让第一个 promise reject 后,因为 then 的第二个参数为 undefined 就啥也不干,让第一个 promise 中 then 的 onRejected 回调和第二个 promise 中 then 的 onRejected 回调也形成链式调用一样。相当于第一个 promise 中的 onRejected 在发送信号,我被执行了,第二个 promise 中真正的我赶紧执行。
前面我们已经知道,只有一种方式才能让第二个 promise 的 onRejected 执行,就是第一个 promise 抛出异常。
所以我们可以通过当 then 的第二个参数为 undefined 时,就添加一个抛出异常的函数进入收集数组中,等待执行,从而启动第二个 promise 中真正的本体执行。
then(onFulfilled, onRejected) {
// 当 onRejected 为 undefined 或其他空值时,就将它替换为一个抛出异常的函数
onRejected = onRejected || ((err) => { throw err });
return new LcPromise() {...}
}
catch(onRejected) {
this.then(undefined, onRejected)
}
finally 方法
无论 promise 是成功还是失败都要执行 finally 方法,由上可知,promise 实际执行的都是 then 方法。所以 finally 的实现无非是这样:
finally(fns) {
this.then(fns, fns)
}
const lcPromise = new LcPromise((resolve, reject) => {
resolve("resolve1");
})
.then((res) => {
console.log("res1: ", res);
return "aaa"
})
.catch((err) => {
console.log("catch: ", err);
})
.finally(() => {
console.log("finally");
});
finally 也是链式调用的,所以 catch 要将第二个 promise 返回。
catch(onRejected) {
return this.then(undefined, onRejected);
}
finally 也会碰到 catch 一样的问题:调用链断掉。这次断在 catch 的 this.(undefined, onRejected)
的 undefined 中。
如上述代码调用,当第一个 promise resolve,第一个 then 中的 onFulfilled 执行,并且拥有返回值。此时就会启动第二个 promise then 中的 onFulfilled 执行,也就是 catch 中的this.(undefined, onRejected)
执行,但是此时 onFulfilled 为 undefined,调用链断了,无法启动第三个 promise 的 then 执行了,也就是无法启 finally 的this.then(fns, fns)
执行,也就是 finally 无法执行。
因此** catch 中的 onFulfilled 参数函数不能为 undefined,它需要是一个有返回值的任意函数,用来启动后续 onFulfilled 执行**。catch 执行的也是 then,所以根上是 then 方法的 onFulfilled 不能为 undefined,改 then 就行。
then(onFulfilled, onRejected) {
// 当 onRejected 为 undefined 或其他空值时,就将它替换为一个抛出异常的函数
onRejected = onRejected || ((err) => { throw err });
// 当 onFulfilled 为 undefined 或其他空值时,就将它替换为一个有返回值的函数
onFulfilled = onFulfilled || ((value) => value);
return new LcPromise() {...}
}
catch(onRejected) {
return this.then(undefined, onRejected)
}
完整实现
const PROMISE_STATUS_PENDING = "pending";
const PROMISE_STATUS_FULFILLED = "fulfilled";
const PROMISE_STATUS_REJECTED = "rejected";
const execFunctionWithCatchError = (execFn, value, resolve, reject) => {
try {
const res = execFn(value);
resolve(res);
} catch (error) {
reject(error);
}
};
class LcPromise {
constructor(executed) {
this.status = PROMISE_STATUS_PENDING;
// 收集 then 的参数
this.onFulfilledFns = [];
this.onRejectedFns = [];
this.value = undefined;
this.reason = undefined;
const resolve = (value) => {
this.value = value;
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING) return;
this.status = PROMISE_STATUS_FULFILLED;
this.onFulfilledFns.forEach((fn) => fn(this.value));
});
};
const reject = (reason) => {
this.reason = reason;
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING) return;
this.status = PROMISE_STATUS_REJECTED;
this.onRejectedFns.forEach((fn) => fn(this.reason));
});
};
executed(resolve, reject);
}
then(onFulfilled, onRejected) {
// 当 onRejected 为 undefined 或其他空值时,就将它替换为一个抛出异常的函数
onRejected =
onRejected ||
((err) => {
throw err;
});
// 当 onFulfilled 为 undefined 或其他空值时,就将它替换为一个有返回值的函数
onFulfilled = onFulfilled || ((value) => value);
return new LcPromise((resolve, reject) => {
// 1. 在 resolve 中执行
if (onFulfilled)
this.onFulfilledFns.push(() => {
execFunctionWithCatchError(onFulfilled, this.value, resolve, reject);
});
if (onRejected)
this.onRejectedFns.push(() => {
execFunctionWithCatchError(onRejected, this.reason, resolve, reject);
});
// 2. fulfilled 状态后收集的参数函数,在自身中执行
if (this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
execFunctionWithCatchError(onFulfilled, this.value, resolve, reject);
}
if (this.status === PROMISE_STATUS_REJECTED && onRejected) {
execFunctionWithCatchError(onRejected, this.reason, resolve, reject);
}
});
}
catch(onRejected) {
return this.then(undefined, onRejected);
}
finally(fns) {
this.then(fns, fns);
}
}