1. Promise核心逻辑实现
-
Promise是一个类,需要在构建函数中传入一个execute的执行函数,并且会立即执行的
-
Promise会提供俩个方法并在execute暴露出来,用以改变Promise的状态。并且可以传入参数,resolve 的参数表示成功的值,rejected的参数表示失败的原因。
-
Promise拥有三种状态(一旦确定就不能更改)
-
PENDING 等待状态
-
FULFILLED 成功状态
-
REJECTED 失败状态
-
Promise上有then函数,用于判断promise 的状态,根据状态调用不同的回调函数。把成功的值或者失败的原因传递下去
因此我们封装一下状态:
const STATUS = {
PENDING: Symbol('pending'),
FULFILLED: Symbol('fulfilled'),
REJECTED: Symbol('rejected')
}
那么Promise的实现如下:
class MPromise {
constructor(executor) {
if (typeof executor === "function") {
executor(this.resolve, this.rejected);
}
}
status = STATUS.PENDING;
value = undefined;
reason = undefined;
resolve = (value) => {
// 如果状态已经改变,禁止再次改变
if (this.status !== STATUS.PENDING) return;
// 将状态修改成fulfilled 成功状态
this.status = STATUS.FULFILLED;
this.value = value;
};
rejected = (reason) => {
// 将状态修改成rejected 失败状态
if (this.status !== STATUS.PENDING) return;
this.status = STATUS.REJECTED;
this.reason = reason;
};
then(successCallBack, errCallBack) {
// 判断promise 的状态,根据状态调用不同的回调函数
if (this.status === STATUS.FULFILLED) {
successCallBack(this.value);
} else if (this.status === STATUS.REJECTED) {
errCallBack(this.reason);
}
}
}
至此,我们实现了Promise的核心逻辑。但是这也只是最基本的功能,下面我们需要完善我们的代码。
2. 异步逻辑处理
当执行函数有异步逻辑时,当前的代码无法满足我们的需求。因此我们需要先把回调函数存储起来,在异步结束之后去执行回调函数。
class MPromise {
constructor(executor) {
if (typeof executor === "function") {
executor(this.resolve, this.rejected);
}
}
status = STATUS.PENDING;
value = undefined;
reason = undefined;
successCallBack = undefined;
errCallBack = undefined;
resolve = (value) => {
// 如果状态已经改变,禁止再次改变
if (this.status !== STATUS.PENDING) return;
// 将状态修改成fulfilled 成功状态
this.status = STATUS.FULFILLED;
this.value = value;
// 如果有成功回调就执行
this.successCallBack && this.successCallBack(this.value);
};
rejected = (reason) => {
// 将状态修改成rejected 失败状态
if (this.status !== STATUS.PENDING) return;
this.status = STATUS.REJECTED;
this.reason = reason;
this.errCallBack && this.errCallBack(this.reason);
};
then(successCallBack, errCallBack) {
// 判断promise 的状态,根据状态调用不同的回调函数
if (this.status === STATUS.FULFILLED) {
successCallBack(this.value);
} else if (this.status === STATUS.REJECTED) {
errCallBack(this.reason);
} else {
// 将回调函数存储起来
this.successCallBack = successCallBack;
this.errCallBack = errCallBack;
}
}
}
3. then函数的多次调用以及链式调用
当我们then函数有多次调用的时候,当前的then函数只会执行一次,所以我们用数组来存储回调函数,循环调用。
// errCallBack = undefined
errCallBackList = [];
// this.errCallBack && this.errCallBack(this.reason);
while (this.errCallBackList.length > 0) this.errCallBackList.shift()();
// this.errCallBack = errCallBack;
this.errCallBackList.push(() => { errCallBack(this.reason);});
then函数的链式调用,说明其返回的是一个新的Promise对象,但是如果then内部的回调函数执行结果是一个值可以直接传递下去,但如果结果依然是一个promise那就把这个promise的结果resolve出去。
因此我们需要判断返回值的类型:
function resolvePromise(result, resolve, reject) {
if (result instanceof MPromise) {
result.then(resolve, reject);
} else {
resolve(result);
}
}
then函数代码:
then(successCallBack, errCallBack) {
let nPromise = new MPromise((resolve, rejected) => {
// 判断promise 的状态,根据状态调用不同的回调函数
if (this.status === STATUS.FULFILLED) {
let res = successCallBack(this.value);
resolvePromise(res, resolve, rejected);
} else if (this.status === STATUS.REJECTED) {
let res = errCallBack(this.reason);
resolvePromise(res, resolve, rejected);
} else {
// 将回调函数存储起来
this.successCallBackList.push(() => {
let res = successCallBack(this.value);
resolvePromise(res, resolve, rejected);
});
this.errCallBackList.push(() => {
let res = errCallBack(this.reason);
resolvePromise(res, resolve, rejected);
});
}
});
return nPromise;
}
promise对象循环调用问题:(promise会抛出一个错误:Uncaught (in promise) TypeError: Chaining cycle detected for promise #<Promise>)
let p = new Promise((resolve, rejected) => {
resolve(12);
});
let p2 = p.then((res) => { return p2;});
因此我们需要判断我们返回的Promise是否存在这种问题,我们优化了resolvePromise方法,如下:
function resolvePromise(result,nPromise, resolve, reject) {
if(result === nPromise ){
reject(new TypeError("Uncaught (in promise) TypeError: Chaining cycle detected for promise #<Promise>"))
} if (result instanceof MPromise) {
result.then(resolve, reject);
} else {
resolve(result);
}
}
then函数中的参数都是可选参数,因此我们需要将参数改成可选的,即添加默认值:
successCallBack = typeof successCallBack === "function" ? successCallBack : (value) => this.value;
errCallBack = typeof errCallBack === "function" ? errCallBack : (reason) => this.reason;
4. Promise中的异常处理
1. 执行器中的异常处理
constructor(executor) {
if (typeof executor === "function") {
try {
executor(this.resolve, this.rejected);
} catch (error) {
this.rejected(error)
}
}
}
2. then函数中的异常处理
我们封装一个函数统一处理异常
const handle = (callback,value) => {
setTimeout(() => {
try {
let res = callback(value);
resolvePromise(res, nPromise, resolve, rejected);
} catch (error) {
reject(error);
}
}, 0);
};
我们整体的then函数就完成了:
then(successCallBack, errCallBack) {
successCallBack = typeof successCallBack === "function"? successCallBack : (value) => this.value;
errCallBack = typeof errCallBack === "function" ? errCallBack : (reason) => this.reason;
let nPromise = new MPromise((resolve, rejected) => {
const handle = (callback,value) => {
setTimeout(() => {
try {
let res = callback(value);
resolvePromise(res, nPromise, resolve, rejected);
} catch (error) {
reject(error);
}
}, 0);
};
// 判断promise 的状态,根据状态调用不同的回调函数
if (this.status === STATUS.FULFILLED) {
handle(successCallBack,this.value)
} else if (this.status === STATUS.REJECTED) {
handle(errCallBack,this.reason)
} else {
// 将回调函数存储起来
this.successCallBackList.push(() => {
handle(successCallBack,this.value)
});
this.errCallBackList.push(() => {
handle(errCallBack,this.reason)
});
}
});
return nPromise;
}
5. catch函数的实现
catch方法其实就是也是一个then方法,只是没有成功回调:
catch(callback){
return this.then(null,callback);
}
至此,除了一些的静态方法,我们Promise基本完善了。