如何编写支持Promise.resolve()的Promise polyfill
问题背景
我正在尝试编写Promise polyfill以加深对Promise原理的理解,在网上检索到一段可部分理解的函数式实现代码,但存在几个待解决的问题:
- 无法理解代码中
handlers和catchers数组的作用,资料说明二者用于处理Promise尚未落定(既未fulfilled也未rejected)的场景 - 不理解
resolve、reject方法中遍历两个数组执行回调的两行代码逻辑 - 现有实现不支持类似
let p1 = Promise.resolve("Hello World");的静态调用写法,尝试改写为class类实现版本未成功 - 曾尝试编写
CustomPromise.prototype.resolve = function(error) {...}挂载方法,依然报错CustomPromise.resolve is not a function;类实现版本中未正确实现executor回调逻辑,只需要任意一种实现方案可支持Promise.resolve()调用场景即可。
初始参考代码(函数式版本)
// 注:原代码未定义状态常量,需提前声明 const PENDING = 'pending' const FULFILLED = 'fulfilled' const REJECTED = 'rejected' function CustomPromise(executor) { var state=PENDING; var value = null; var handlers=[]; var catchers = []; function resolve(result) { if(state!==PENDING) return; state=FULFILLED; value = result; handlers.forEach((h)=>h(value)); // 待解释的遍历逻辑 } function reject(error) { if(state!==PENDING)return; state=REJECTED; value=error; catchers.forEach(c=>c(value)); // 待解释的遍历逻辑 } this.then = function(successCallback) { if(state === FULFILLED) { successCallback(value); }else { handlers.push(successCallback); } return this; } this.catch = function(failureCallback) { if(state===REJECTED){ failureCallback(value) } else { catchers.push(value); // 原代码此处存在bug } } executor(resolve,reject); }
存在问题的自写类版本
const PENDING = 'pending' const FULFILLED = 'fulfilled' const REJECTED = 'rejected' class CustomPromise { constructor(callback){ this.state = PENDING; this.executor = callback; this.value = null; this.handlers = []; this.catchers = []; this.then = function(successCallback) { if(this.state === FULFILLED) { successCallback(this.value); }else { this.handlers.push(successCallback); } return this; }; this.catch = function(failureCallback) { if(this.state===REJECTED){ failureCallback(this.value) } else { this.catchers.push(this.value); // 同函数式版本的bug } }; } static resolve(result) { if(this.state!==PENDING) return; this.state=FULFILLED; this.value = result; this.handlers.forEach((h)=>h(this.value)); } static reject(error) { if(this.state!==PENDING)return; this.state=REJECTED; this.value=error; this.catchers.forEach(c=>c(this.value)); } }
核心逻辑解释
handlers和catchers数组的作用
Promise支持异步状态落定:当调用.then/.catch注册回调时,Promise很可能还处于PENDING状态(比如封装了setTimeout、接口请求等异步操作),此时传入的成功/失败回调不能立刻执行,需要先暂存。
handlers:存储PENDING状态下通过.then注册的所有成功回调catchers:存储PENDING状态下通过.catch注册的所有失败回调
注:两份初始代码的
catch方法都存在bug:PENDING状态下应该把传入的failureCallback推入catchers数组,原代码错误推入了value,会导致后续reject时执行报错。
遍历数组执行回调的逻辑
Promise状态只能从PENDING变更为FULFILLED/REJECTED,且一旦变更不可逆。当调用resolve将状态改为FULFILLED、调用reject将状态改为REJECTED时,需要把之前暂存的所有对应回调按注册顺序依次执行,传入最终的结果/错误值,这就是两行遍历代码的作用。
静态方法报错原因
给CustomPromise.prototype挂载方法,是给Promise实例添加方法,需要通过new CustomPromise().resolve()的形式才能调用;而CustomPromise.resolve()是直接将构造函数/类本身作为对象调用方法,属于静态方法,需要直接挂载到构造函数对象上,类中用static关键字定义的方法就会挂载到类本身,而非原型链。
修正后可运行的函数式实现版本(支持静态调用)
修正了原代码的bug,补全了executor执行逻辑、静态resolve/reject实现,同时支持基础的链式调用:
const PENDING = 'pending' const FULFILLED = 'fulfilled' const REJECTED = 'rejected' function CustomPromise(executor) { this.state = PENDING this.value = null this.handlers = [] this.catchers = [] const resolve = (result) => { if (this.state !== PENDING) return // 支持resolve传入Promise实例的场景 if (result instanceof CustomPromise) { return result.then(resolve, reject) } this.state = FULFILLED this.value = result this.handlers.forEach(cb => cb(this.value)) } const reject = (error) => { if (this.state !== PENDING) return this.state = REJECTED this.value = error this.catchers.forEach(cb => cb(this.value)) } this.then = function(onFulfilled, onRejected) { // 链式调用必须返回新的Promise实例 return new CustomPromise((resolveNext, rejectNext) => { const handleSuccess = (val) => { try { const res = onFulfilled ? onFulfilled(val) : val resolveNext(res) } catch (err) { rejectNext(err) } } const handleFail = (err) => { try { const res = onRejected ? onRejected(err) : err onRejected ? resolveNext(res) : rejectNext(res) } catch (e) { rejectNext(e) } } if (this.state === FULFILLED) { handleSuccess(this.value) } else if (this.state === REJECTED) { handleFail(this.value) } else { this.handlers.push(handleSuccess) this.catchers.push(handleFail) } }) } this.catch = function(onRejected) { return this.then(null, onRejected) } // 执行用户传入的executor,捕获同步错误 try { executor(resolve, reject) } catch (err) { reject(err) } } // 直接挂载静态方法到构造函数 CustomPromise.resolve = function(value) { if (value instanceof CustomPromise) return value return new CustomPromise(resolve => resolve(value)) } CustomPromise.reject = function(error) { return new CustomPromise((_, reject) => reject(error)) }
测试用例
// 测试静态resolve const p1 = CustomPromise.resolve("Hello World") p1.then(res => console.log(res)) // 输出 Hello World // 测试异步场景 const p2 = new CustomPromise((resolve) => { setTimeout(() => resolve("异步执行成功"), 1000) }) p2.then(res => console.log(res)) // 1秒后输出 异步执行成功 // 测试链式调用 CustomPromise.resolve(1).then(res => res + 2).then(res => console.log(res)) // 输出3
内容的提问来源于stack exchange,提问作者era s'q

