在之前的逻辑中,只是对promise一些基础功能,进行了原理剖析,并没有对异常进行捕获及处理,那么接下来我们,就需要对这些异常进行捕获,并完善我们的代码。
具体需要捕获异常的,在逻辑中有哪些地方:
- 执行器里面的代码异常;
then方法成功回调,代码异常;then方法失败回调,代码异常;then方法异步逻辑成功回调,代码异常;then方法异步逻辑失败回调,代码异常;
针对以上代码异常,我们需要捕获到这些错误,并抛出,且在发生异常是,代码还能继续执行,这里需要用到try...catch方法,如果发生了错误,就调用reject方法,并传递错误原因。
**try...catch**介绍:
try...catch:程序发生错误时,能继续执行try:监控可能发生异常的代码块catch:捕获try里面发生的错误进行处理
我们在catch中抛出异常,文章中测试及新增代码只写改动部分,全局代码会在文章最后。
1.执行器中的代码异常:
// 执行器中捕获异常
constructor (executor) {
try {
// 执行器接收两个参数
executor(this.resolve, this.reject);
} catch (error) {
// 如果有异常发生,调用reject方法,
this.reject(error);
}
}
**index.js**中测试用例:
const testPromise = require ("./test-promise");
let promise = new testPromise ((resolve, reject) => {
// 执行器中抛出错误
throw new TypeError ("executor error");
})
// 6.1 测试执行器发生错误
promise.then(value => {
console.log(value);
}, reason => {
console.log("捕获错误>>>", reason);
})
执行结果:
**2.then方法成功回调代码异常:**当前then方法回调函数发生异常,需要捕获到并传递给下一个then调用,在下一个then的回调函数的reject方法中捕获到。
**testPromise.js**中:
if (this.status === FULFILLED) {
setTimeout(() => {
try {
let x = successCallback(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
// 这里调用的是下一个then方法的reject方法,而不是this.reject
reject(error);
}
}, 0)
}
**index.js**中测试用例:
// 6.2 then方法的成功回调函数 异常
promise.then(value => {
// then方法成功回调中 异常 传递给下个
throw new Error ("successCallback error");
})
// 在第二个then方法捕获
.then(value => {}, reason => {
console.log("捕获【then方法成功回调】错误>>>", reason);
})
执行结果:
**3.then方法失败回调代码异常:**原理同成功的回调
**testPromise.js**中:
else if (this.status == REJECTED) {
// failCallback(this.reason);
setTimeout(() => {
try {
let x = failCallback(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0)
}
**index.js**中测试用例:
// 6.3 then方法的失败回调函数 异常
promise.then(value => {
},reason => {
throw new Error ("failCallback error");
})
// 在第二个then方法捕获
.then(value => {}, reason => {
console.log("捕获【then方法失败回调】错误>>>", reason);
})
执行结果:
4.then方法异步逻辑成功回调 && 5.then方法**异步逻辑失败回调****:**同理上面,直接代码
**testPromise.js**中:
// resolve实例方法中
while (this.successValue.length) this.successValue.shift()(this.value)
// 改为👇👇👇👇
while (this.successValue.length) this.successValue.shift()()
// reject实例方法中
while (this.failReason.length) this.failReason.shift()(this.value) // 改为👇👇👇👇
while (this.failReason.length) this.failReason.shift()()
---------------------------------
// 如果在此出对代码进行了处理,已经将当前调用值传递给下个then,那么之前resolve和reject方法就直接执行即可,不需要在传值,如上👆
else {
// try..catch中无法处理,所以改为push一个方法进去,在这个方法对回调函数进行异常捕获
// this.successValue.push(successCallback);
// this.failReason.push(failCallback);
this.successValue.push(() => {
setTimeout(() => {
try {
let x = successCallback(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0)
});
this.failReason.push(() => {
setTimeout(() => {
try {
let y = failCallback(this.reason);
reject(y);
} catch (error) {
reject(error);
}
}, 0)
});
return;
}
**index.js**中测试:
// 6.4 then方法的异步回调函数 异常
promise.then(value => {
throw new Error ("异步 error");
},reason => {
console.log("捕获【then方法异步回调】错误111>>>", reason);
})
// 在第二个then方法捕获
.then(value => {}, reason => {
console.log("捕获【then方法异步回调】错误>>>", reason);
})
测试结果:
至此,完成了逻辑中异常捕获:
testPromise中:
// 定义状态
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class testPromise {
/**
* 通过构造函数constructor接收传入的回调函数
* 构造函数不能被直接调用,必须通过new运算符在创建对象时才会自动调用,
* 当我们外部调用new myPromise()生成实例时,consctructor构造方法会执行,executor执行器立即执行
*
* executor代表执行器,会立即执行
*/
constructor (executor) {
try {
// 执行器接收两个参数
executor(this.resolve, this.reject);
} catch (error) {
this.reject(error);
}
}
/**
* 初始状态为等待
* 每个promise独有的
*/
status = PENDING;
// 定义成功的值
value = undefined;
// 定义失败的值
reason = undefined;
// 定义异步中【等待】状态的存储成功回调函数
// successValue = undefined;
// 重复调用then,使用数组存储
successValue = [];
// 定义异步中【等待】状态的存储失败回调函数
failReason = [];
// 调用resolve后传递成功的值
resolve = value => {
// resolve作用是修改状态为成功且不可更改,修改状态之前需要判断当前状态是否为等待,如果不是就返回
if (this.status !== PENDING) return;
this.status = FULFILLED;
// 保存成功之后的值
this.value = value;
// 处理异步,判断successValue是否有值,如果有就调用successCallback方法,并传入此时调用的值参数
// console.log("successValue>>>", this.successValue); // [Function (anonymous)]
/**
* 1.此时的successValue存放的是successCallback这个回调函数,
* 在调用2s后,执行resolve方法后,状态变为fulfilled,
* 那么调用then方法,即调用成功后的回调函数,此时this.successValue就是这个回调函数
* if (this.successValue) this.successValue(this.value);
*
* 2.重复调用then方法,那么就需要把存储在数组中的回调函数依次执行
* 且倒叙排列,让第一个进入数组的先执行
* while (this.successValue.length) this.successValue.shift()(this.value);
*/
while (this.successValue.length) this.successValue.shift()();
}
// 调用reject后传递失败的原因
reject = reason => {
if (this.status !== PENDING) return;
this.status = REJECTED;
// 保存失败原因
this.reason = reason;
// 异步调用
// if (this.failReason) this.failReason(this.reason);
while (this.failReason.length) this.failReason.shift()();
}
/**
* then方法
* 判断状态
* 定义在promise原型对象上的,
* 作用是指定resolved状态的回调函数或者rejected状态的回调函数。
* 也就是说resolve或reject方法更改promise的状态后,根据当前的状态,调用相应的回调函数
*/
then (successCallback, failCallback) {
/**
* 判断状态,并根据状态指定相应的回调函数
* 那么成功后的值,失败后的值在哪呢,就是resolve和reject方法在调用后传递的值
*
* 普通链式调用见下面1、2、3步
*/
let promise2 = new testPromise ((resolve, reject) => {
if (this.status === FULFILLED) {
setTimeout(() => {
try {
// 2.保存上一次then方法回调函数的返回值
let x = successCallback(this.value);
// 3.将上一次回到函数的返回值作为参数,传递给下一个then方法调用
// resolve(x);
/**
* 如果这里传入的是普通值,那么直接调用resolve方法,并把当前值传递给下一个promise对象
* 如果传入的是promise对象,那么需要先判断下promise状态,根据状态决定调用resolve还是reject,
* 并把相应的成功值或失败原因传给下一个promise对象
*
* 这里如果是异步还有重复调用resolve或reject方法,那么就把这个方法单独写出来,即用即调
* 此方法需要的参数即我们这里提到的三个:x、resolve、reject
*
* 传入promise2用于和x做判断,这里会有个问题就是,如果是异步执行那么这里是在then执行中传入,
* 那么此时就会找不到这个promise2,所以这里调整为异步执行,在当前then方法执行完后再传入返回的promise2
*/
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
// 这里调用的是下一个then方法的reject方法,而不是this.reject
reject(error);
}
}, 0)
} else if (this.status === REJECTED) {
setTimeout(() => {
try {
let y = failCallback(this.reason);
reject(y);
} catch (error) {
reject(error);
}
}, 0)
} else {
/**
* 在此处理异步情况,因为如果异步调用,此时promise状态为等待
* 此时调用不了成功或失败,因为不知道是成功还是失败
* 那么就需要把成功回调和失败回调存储,调用2s结束后,再调用相应的回调
*/
// 存储成功or失败的值,存储后就需要再2s后调用resolve方法,那么就需要在resolve方法中判断是否有successCallback
// this.successValue = successCallback;
// this.failReason = failCallback;
/**
* then方法重复调用,非链式调用
* 如果是同步,那么就有明确的状态,即走上面的fulfilled判断或者rejected判断即可
* 如果是异步,就需要存储这些异步的回调,在2s后依次执行
* 多个then方法调用,就需要使用数组存储
*/
// try..catch中无法处理,所以改为push一个方法进去,在这个方法对回调函数进行异常捕获
// this.successValue.push(successCallback);
// this.failReason.push(failCallback);
this.successValue.push(() => {
setTimeout(() => {
try {
let x = successCallback(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0)
});
this.failReason.push(() => {
setTimeout(() => {
try {
let y = failCallback(this.reason);
reject(y);
} catch (error) {
reject(error);
}
}, 0)
});
return;
}
})
// 1.返回promise对象
return promise2
}
}
function resolvePromise(promise2, x, resolve, reject) {
console.log(promise2 === x);
// 拦截循环调用then方法返回的promise对象
if (promise2 === x) {
return reject(new TypeError("Chaining cycle detected for promise #<Promise>"));
}
/**
* 判断普通值
* 方法:判断这个x是不是属于testPromise类的一个实例即可
*/
if (x instanceof testPromise) {
/**
* promise对象,需要调用这个promise对象的then方法,
* 那么then方法前面提过,接收成功和失败的回调函数作为参数,并把相应的value和reason传递下去
*/
// x.then(value => resolve(value), reason => reject(reason))
// 可简化为
x.then(resolve, reject);
} else {
// 普通值
resolve(x)
}
}
module.exports = testPromise;
**index.js**测试代码:
const testPromise = require ("./test-promise");
let promise = new testPromise ((resolve, reject) => {
// 异步调用
setTimeout(() => {
resolve("成功 .....");
}, 2000)
// 6.1测试执行器发生错误
// throw new Error ("executor error");
// resolve("成功");
// reject("失败");
})
// 6.1测试执行器发生错误
// promise.then(value => {
// console.log(value);
// }, reason => {
// console.log("捕获【执行器】错误>>>", reason);
// })
// 6.2 then方法的成功回调函数 异常
// promise.then(value => {
// // then方法成功回调中 异常 传递给下个
// throw new Error ("successCallback error");
// })
// // 在第二个then方法捕获
// .then(value => {}, reason => {
// console.log("捕获【then方法成功回调】错误>>>", reason);
// })
// 6.3 then方法的失败回调函数 异常
// promise.then(value => {
// },reason => {
// throw new Error ("failCallback error");
// })
// // 在第二个then方法捕获
// .then(value => {}, reason => {
// console.log("捕获【then方法失败回调】错误>>>", reason);
// })
// 6.4 then方法的异步成功回调函数 异常 && 6.5 then方法的异步失败回调函数 异常
promise.then(value => {
throw new Error ("异步 error");
},reason => {
console.log("捕获【then方法异步回调】错误111>>>", reason);
})
// 在第二个then方法捕获
.then(value => {}, reason => {
console.log("捕获【then方法异步回调】错误>>>", reason);
})