✨ 摘要
在上一篇中,我们实现了简易版 Promise 的链式调用功能。但是不能只有 resolve 没有 reject,这就像只会夸人不会批评——不完整!😅
这篇文章就来继续完善,实现完整的 reject - catch - finally 流程支持。
📜 官方Promise demo Mvp
const violet = new Promise((res, rej) => {
console.log('1. real promise log')
rej('2. error info is reject')
}).then(() => {}, (err) => {
console.log(err, '---get error')
return new Promise((res, rej) => {
res('3. hello world!!!')
})
}).then((res) => {
console.log(res, '\n4. second then is running')
})
🔍 控制台打印结果
1. real promise log
2. error info is reject ---get error
3. hello world!!!
4. second then is running
解释一下:
- 第一个 Promise 中执行 rej,所以走 then 的第二个参数 onRejected
- onRejected 返回一个新的 Promise,进入下一个 then
- 整体流程仍然是链式的,reject 不会中断链条(只要你正确处理)
🚫 Reject 流程实现
我们要补充一个 reject 方法,它的结构和 resolve 类似,不过重点在于:
- 如果 reject 的参数本身是一个 thenable,我们也需要链式等待它完成
- 在 handle 调用时,正确触发 onRejected
- 最后也需要遵守Promise A+规范,使用setTimeout进行exec
function reject (error) {
const fn = () => {
if (state !== STATUS_ENUM.PENDING) return
if (error && (typeof error === 'object' || typeof error === 'function')) {
const { then: customThenFn } = error
if (typeof customThenFn === 'function') {
customThenFn.call(error, resolve, reject)
return
}
}
state = STATUS_ENUM.REJECTED
value = error
handleCb()
}
setTimeout(fn, 0) // 异步触发,符合 Promise A+ 规范
}
🧠 回到链式调用逻辑
来看这段代码中的核心逻辑:
const violet = new Promise((res, rej) => {
console.log('1. real promise log')
rej('2. error info is reject')
}).then(() => {}, (err) => {
console.log(err, '---get error')
return new Promise((res, rej) => {
res('3. hello world!!!')
})
})
你可能已经注意到——
❗ 那个handle函数还不够(因为没有调用onRejected方法)
初始版本的 handle 只支持处理 resolve:
function handle (callback) {
if (state === STATUS_ENUM.PENDING) {
callbacks.push(callback)
return
}
if (state === STATUS_ENUM.FULFILLED) {
if (!callback.onFulfilled) {
callback.resolve(value)
return
}
const ret = callback.onFulfilled(value)
callback.resolve(ret)
}
}
但是我们现在有 reject !我们必须扩展它:
function handle (callback) {
if (state === STATUS_ENUM.PENDING) {
callbacks.push(callback)
return
}
const isFulfilled = state === STATUS_ENUM.FULFILLED
const cb = isFulfilled ? callback.onFulfilled : callback.onRejected
const next = isFulfilled ? callback.resolve : callback.reject
if (!cb) {
next(value)
return
}
try {
const ret = cb(value)
next(ret)
} catch (err) {
callback.reject(err)
}
}
✅ 改进点:
- try...catch 捕获执行错误,避免未捕获异常
- 状态判断明确,支持 rejected 状态回调
🧩 then 方法注入 onRejected
我们还要确保 .then(onFulfilled, onRejected) 能把 onRejected 正确传入:
this.then = function (onFulfilled, onRejected) {
return new ViPromise ((resolve, reject) => {
handle({
onFulfilled,
onRejected,
resolve,
reject
})
})
}
最后,别忘了运行用户的 executor 函数(也要传入reject):
fn(resolve, reject) // 执行用户传入的函数
✅ ViPromise reject 测试
我们重新跑一遍验证逻辑:
const violet = new ViPromise((res, rej) => {
console.log('1. real promise log')
rej('2. error info is reject')
}).then(() => {}, (err) => {
console.log(err, '---get error')
return new Promise((res, rej) => {
res('3. hello world!!!')
})
}).then((res) => {
console.log(res, '\n4. second then is running')
})
控制台打印:
1. real promise log
2. error info is reject ---get error
3. hello world!!!
4. second then is running
流程和原生 Promise 一致,说明我们的 ViPromise 的 reject 支持已经 ✅OK!
🚫 catch 异常处理实现
对于程序产生的错误,我们通常使用try...catch进行捕获,并设置promise状态为reject即可,于是我们补充handle逻辑
function handle (callback) {
if (state === STATUS_ENUM.PENDING) {
callbacks.push(callback)
return
}
const isFulfilled = state === STATUS_ENUM.FULFILLED
const cb = isFulfilled ? callback.onFulfilled : callback.onRejected
const next = isFulfilled ? callback.resolve : callback.reject
// 没传入,默认reject
if (!cb) {
next(value)
return
}
try {
const ret = cb(value)
next(ret)
} catch (e) {
callback.reject(e)
}
}
然后还需要创建一个catch方法,只是声明式我们定义catch用来接受错误的处理,但是其实也是直接调用then方法
this.catch = function (onError) {
this.then(null, onError)
}
✅ ViPromise catch 测试
我们修改样例:
const violet = new ViPromise((res, rej) => {
console.log('1. real promise log')
rej('2. error info is reject')
}).then(() => {}, (err) => {
console.log(err, '---get error')
return new Promise((res, rej) => {
// res('3. hello world!!!')
rej('报错了!混蛋!!!')
})
}).then((res) => {
console.log(res, '\n4. second then is running')
}).catch(e => {
console.log(e, '---catch is running')
})
控制台打印:
1. real promise log
2. error info is reject ---get error
报错了!混蛋!!! ---catch is running
🚀 Finally 处理实现
其实在程序最后,不管Promise状态如何,会有业务需要进行一些收尾工作,这常常就会放在finally中进行,所以finally的执行并不关心promise的成功与否
function Promise(fn){
...
this.catch = function (onError){
this.then(null,onError)
}
this.finally = function (onDone){
this.then(onDone,onDone)
}
...
}
🧾 总结
🔧 到目前为止,我们完成了 ViPromise 的核心功能:
- ✅ 支持 resolve
- ✅ 支持 reject
- ✅ 支持 catch语法糖
- ✅ 支持 finally
- ✅ 支持 then 链式调用,错误回调
- ✅ 异步执行,符合 A+ 规范
👀 你是否也实现过自己的 Promise?欢迎在评论区贴出你的实现,或者告诉我你踩过哪些坑!