添加 catch()
Promise.prototype.catch = function (onRejected) {};
catch() 返回结果也是一个 Promise 对象,我们可以直接去调用 then()
Promise.prototype.catch = function (onRejected) {
return this.then(undefined, onRejected)
};
现在要实现链式异常穿透:修改之前的代码
function Promise(executor) {
const self = this
this.PromiseState = 'pending'
this.PromiseResult = null
this.callbacks = [];
function resolve(data) {
if (self.PromiseState !== 'pending') return
self.PromiseState = 'resolved'
self.PromiseResult = data
self.callbacks.forEach((item) => {
item.onResolved(self.PromiseResult);
});
}
function reject(data) {
if (self.PromiseState !== 'pending') return
self.PromiseState = 'rejected'
self.PromiseResult = data
self.callbacks.forEach((item) => {
item.onRejected(self.PromiseResult);
});
}
try {
executor(resolve, reject);
} catch (e) {
reject(e)
}
}
Promise.prototype.then = function (onResolved, onRejected) {
const self = this;
return new Promise((resolve, reject) => {
function callback(type) {
try {
let result = type(self.PromiseResult);
if (result instanceof Promise) {
result.then(
(v) => {
resolve(v);
},
(r) => {
reject(r);
}
);
} else {
resolve(result);
}
} catch (e) {
reject(e);
}
}
if (this.PromiseState === "resolved") {
callback(onResolved);
}
if (this.PromiseState === "rejected") {
callback(onRejected);
}
if (this.PromiseState === "pending") {
this.callbacks.push({
onResolved: function () {
callback(onResolved);
},
onRejected: function () {
callback(onRejected);
},
});
}
});
};
Promise.prototype.catch = function (onRejected) {
return this.then(undefined, onRejected)
};
此时如果执行异常穿透会报错
let p = new Promise((resolve, reject) => {
setTimeout(() => {
reject("ok");
}, 1000);
});
p.then((value) => {
console.log(111);
})
.then((value) => {
console.log(222);
})
.then((value) => {
console.log(333);
})
.catch((reason) => {
console.warn(reason);
});
先从同步讲,执行完 new Promise,所以实例p在第一次调用then()方法的时候,处于pending状态,他要对这个回调函数onSolved和onRejected进行保存,因为没有onRejected,所以是undefined,当这个状态修改完以后会去调用这个回调函数(前面讲过的异步任务,会将then()方法的回调函数存储在callbacks属性里),但是此时 onRejected是undefined,他不是个函数,所以就会报错,所以此时第一次then()方法p.then()返回的是一个失败的Promise。同理第二个then,第三个then也是这样,一直到catch()去处理这个错误,也就是刚才截图控制器打印出来的错误。
内置的Promise是允许链式调用不传第二个回调函数也就是onRejected的,所以我们也要允许
所以我们要继续修改 then() 方法
Promise.prototype.then = function (onResolved, onRejected) {
const self = this;
// 为了实现异常穿透,判断 onRejected是不是函数
if (typeof onRejected !== "function") {
// 如果不是函数,就要给 oneJected 一个初始值,而不是为 undefined
onRejected = (reason) => {
throw reason;
};
}
return new Promise((resolve, reject) => {
function callback(type) {
try {
let result = type(self.PromiseResult);
if (result instanceof Promise) {
result.then(
(v) => {
resolve(v);
},
(r) => {
reject(r);
}
);
} else {
resolve(result);
}
} catch (e) {
reject(e);
}
}
if (this.PromiseState === "resolved") {
callback(onResolved);
}
if (this.PromiseState === "rejected") {
callback(onRejected);
}
if (this.PromiseState === "pending") {
this.callbacks.push({
onResolved: function () {
callback(onResolved);
},
onRejected: function () {
callback(onRejected);
},
});
}
});
};
此时如果发现没有传 onRejected,会自动给 onRejected赋值一个函数去抛出异常,就可以实现链式异常穿透
拓展:Promise除了异常穿透之外,还有另外一个特性,就是值传递。
也就是说,我第一个回调函数 onResolved函数不传也行
let p = new Promise((resolve, reject) => {
setTimeout(() => {
reject("ok");
}, 1000);
});
p.then()
.then()
.then()
.catch((reason) => {
console.warn(reason);
});
也会成功进行异常穿透
所以我们还要对then()方法进行改进,再判断一下 onResolved函数
Promise.prototype.then = function (onResolved, onRejected) {
const self = this;
// 为了实现异常穿透,判断 onRejected是不是函数
if (typeof onRejected !== 'function') {
// 如果不是函数,就要给 oneJected 一个初始值,而不是为 undefined
onRejected = reason => {
throw reason
}
}
// 为了实现值传递,判断 onResolved是不是函数
if (typeof onResolved !== 'function') {
// 如果不是函数,就要给 oneJected 一个初始值,而不是为 undefined
onResolved = value => value
}
return new Promise((resolve, reject) => {
function callback(type) {
try {
let result = type(self.PromiseResult);
if (result instanceof Promise) {
result.then(
(v) => {
resolve(v);
},
(r) => {
reject(r);
}
);
} else {
resolve(result);
}
} catch (e) {
reject(e);
}
}
if (this.PromiseState === "resolved") {
callback(onResolved);
}
if (this.PromiseState === "rejected") {
callback(onRejected);
}
if (this.PromiseState === "pending") {
this.callbacks.push({
onResolved: function () {
callback(onResolved);
},
onRejected: function () {
callback(onRejected);
},
});
}
});
};