如何用JavaScript实现简易Promise并解决catch错误处理及链式调用问题
自定义Promise错误处理修复方案
现有代码核心问题
- 缺少Promise状态管理:未定义
pending/fulfilled/rejected三种状态,状态变更后没有锁死,导致reject执行后仍会触发resolve逻辑,then回调不会被中断 - 链式调用返回值错误:then/catch方法直接返回当前实例
this,不符合原生Promise每次调用then/catch返回新Promise实例的规范,导致错误无法沿链式调用冒泡 - 未存储Promise的终值/拒因:异步场景下如果resolve/reject执行时回调还未注册,会丢失结果,也无法判断当前Promise的最终状态
轻量实现调整代码
直接修改Promise.mjs的代码如下:
export default class _Promise { // 定义三个状态常量 static PENDING = 'pending'; static FULFILLED = 'fulfilled'; static REJECTED = 'rejected'; constructor(executor) { // 初始化状态、终值、拒因、回调队列 this.status = _Promise.PENDING; this.value = null; this.reason = null; this.fulfilledCallbacks = []; this.rejectedCallbacks = []; if (executor && executor instanceof Function) { try { executor(this.resolve.bind(this), this.reject.bind(this)); } catch (error) { this.reject(error); } } } resolve(value) { // 只有pending状态才能变更状态 if (this.status !== _Promise.PENDING) return; this.status = _Promise.FULFILLED; this.value = value; // 执行所有注册的成功回调 this.fulfilledCallbacks.forEach(cb => cb(value)); } reject(reason) { if (this.status !== _Promise.PENDING) return; this.status = _Promise.REJECTED; this.reason = reason; // 执行所有注册的失败回调 this.rejectedCallbacks.forEach(cb => cb(reason)); } then(onFulfilled, onRejected) { // 处理可选参数,默认透传值/错误 onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v; onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err }; // 每次then返回新的Promise实例,实现链式调用 return new _Promise((resolve, reject) => { // 包装回调,处理返回值的Promise穿透 const handleFulfilled = () => { try { const result = onFulfilled(this.value); // 如果回调返回的是Promise,等待其状态变更 result instanceof _Promise ? result.then(resolve, reject) : resolve(result); } catch (err) { reject(err); } }; const handleRejected = () => { try { const result = onRejected(this.reason); result instanceof _Promise ? result.then(resolve, reject) : resolve(result); } catch (err) { reject(err); } }; // 根据当前状态处理回调 if (this.status === _Promise.PENDING) { this.fulfilledCallbacks.push(handleFulfilled); this.rejectedCallbacks.push(handleRejected); } else if (this.status === _Promise.FULFILLED) { setTimeout(handleFulfilled, 0); // 模拟异步执行 } else if (this.status === _Promise.REJECTED) { setTimeout(handleRejected, 0); } }) } catch(onRejected) { return this.then(null, onRejected); } }
调整后效果验证
- 传入非法参数触发reject时,会直接跳过所有后续的成功回调,错误沿链式调用冒泡到最近的catch方法,不会抛出未处理异常
- 嵌套then中抛出的错误会向外层冒泡,外层catch可以正常捕获
- 异步执行逻辑和链式调用返回值符合预期,原有正常流程的执行结果不受影响
内容的提问来源于stack exchange,提问作者cj-2307
相关产品推荐
相关产品推荐

