首先,对于这个catch方法来说,是很简单的,因为它只帮我们做了一件事,那就是调用失败的回调,如下:
let p1 = new Promise((resolve, reject) => {
reject("Oh no")
})
p1.then(value => {
console.log("ok")
}).then(value => {
console.log("ok")
}).catch(reason => {
console.log(reason)
})
结果:
但是,随之出现了一个问题,有关异常穿透的问题。那么称之为异常穿透呢,我们先改变一下上面的代码观察一下会出现上面情况:
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("Oh no")
}, 1000);
})
p1.then(value => {
console.log("ok")
}).then(value => {
console.log("ok")
}).catch(reason => {
console.log(reason)
})
结果:
解释:
?因为此时的代码为异步调用,声明了p1这个Promise之后没有立即执行reject函数改变状态,然而代码会同步执行下面的链式调用部分,当你调用then方法后值传入了成功的回调,而失败的回调则是undefined,所以就会报错。
这时候我们就要再次优化我们的then方法,怎么优化呢? 在then方法的入口处进行一次判断,判断传入的成功和失败的回调是否为函数,如果不是函数,那么我们就给他改成一个函数,失败的回调将传入的回调抛出一个reason,那么这时候他就会去调用reject函数,然后链式调用往下走,传入的失败的回调又是一个undefined(不是函数),那么我们如上改变,最终就会被最后调用的catch给捕获到,就做到了异常穿透。而成功的回调呢,我们需要将其变成一个成功的回调传入,但是不起作用,因为传入的是undefined,所以我们不需要做任何操作,只需跳过该层即可,当碰到了有传入成功的会调的时候,自然就会传出值,这便是值传递,类似于异常穿透,这样我们就可以得到一个优化后的then方法:
// then 方法封装
Promise.prototype.then = function (onResolved, onRejected) {
//保存实例对象
const self = this
// 判断回调函数参数
if (typeof onRejected !== "function") {
onRejected = reason => {
throw reason
}
}
if (typeof onResolved !== "function") {
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 {
reject(result)
}
} catch (e) {
reject(e)
}
}
if (this.Promise.PromiseState === "fulfilled") {
callback(onResolved)
}
if (this.Promise.PromiseState === "rejected") {
callback(onRejected)
}
if (this.Promise.PromiseState === "pending") {
// 当有多个回调时 有多少个会调 都要保存 ,
// 所以这里 咱们所有的实例的方法都压入一个数组中
this.callbacks.push({
onResolved: function () {
callback(onResolved)
},
onRejected: function () {
callback(onRejected)
}
})
}
})
}
// all 方法封装
Promise.all = function (promises) {
// 返回结果为Promise对象
return new Promise((resolve, reject) => {
// 计数器
let count = 0
// 存放返回结果 【数组】
let arr = []
// 遍历promises
for (let i = 0; i < promises.length; i++) {
promises[i].then(v => {
// 当计数器的值等于promise的长度时 , 表示传入的promises中
// 所有的promise对象都是成功的,此时才需要改变返回的promise
// 的状态为成功,否则,计数器加一(count++)
arr[i] = v
if (count === promises.length) {
resolve(arr)
}
}, r => {
reject(r)
})
}
})
}
至于catch的封装,就如本文的第一段话一样,只帮我们做了一件事,那就是调用失败的回调,那么封装起来也就一句话了,抓取失败的回调呗,如下:
// 添加 catch 方法
Promise.prototype.catch = function (onRejected) {
return this.then(undefined, onRejected)
}
至此,重要的几个函数以及函数我们就大致封装完毕了,下篇我们将会对一些剩余的较为简单的方法全部封装完最后会提供一个Promise手写的汇总,以及class版本,以及一些有关Promise关键性问题的汇总。
接下来会有相关文章持续更新之后的Promise的优化和相关的 then() 、all() 等函数的封装
|