看了一些有关Promise/A+规范实现的文章,也看了看V8源码中有关部分的实现,网上对Promise/A+的实现有很多,但很多与原生行为相去甚远,个人也尝试实现了一个,并尽量模拟原生行为,由于并没有(或者没找到)有关Promise符合原生行为的测试库,所以可能有漏洞,望指正。
代码仓库
https://github.com/LuHawXem/HandwrittenPromise
代码分析
- 定义用于存储回调函数的结点类PromiseReaction,存储当Promise完成(fulfilled或rejected)时的回调函数
1 | /** |
2.定义用于处理resolve过程的函数resolvePromise,由于resolve函数可以接受一个任意类型的实例作为参数,则其中包含各类基本类型及引用类型,以及Promise/A+规范中定义的thenable对象,所以需要进行多次类型判断,此处thenable对象的处理即个人进行测试与原生是否相符时的重点,thenable对象即一个存在then方法的对象,它可以是Promise对象(Promise的原型链上定义了then方法),也可以是一个含有then方法的普通对象(如:{ then: x => x }
),此两种thenable对象传入原生Promise的resolve时会表现出些微差别,此处将此种差别模拟出来,除此以外,promise不能等待自己完成自己,因此进行promise === x
的判断,其他的非thenable类型均直接调用传入的resolve方法
1 | /** |
3.定义用于处理回调函数链表的函数,在V8代码中,Promise的回调函数/结果保存在字段reactions_or_result
中,值可以为Zero
、PromiseReaction
和JSAny
,分别表示无回调函数也无结果、回调函数链表(此时为pending状态)、完成结果(此时为fulfilled或rejected),并且回调函数链表为反向链表,即第一个添加的结点会在链表尾部,因此在处理的时候需要先进行链表反转
1 | /** |
4.SelfPromise类,目前只实现了构造函数,原型链上的then方法、catch方法,和静态的(即不在原型链上,在原对象上)resolve方法、reject方法,finally、all、race等其他一些方法暂未实现
4.1.构造函数接收一个函数作为参数,原生Promise给予的代码提示为(resolve: (value: any) => void, reject: (reason: any) => void) => void
,个人实现的代码提示为(arg0: (value: any) => void, arg1: (reason: any) => void) => any
,对JSDoc格式的注释还不太了解,献丑😃
将status和reactions_or_result添加到this对象上(JS的new本质上就是返回函数中的this对象),V8代码中还有has_handler,handled_hint、async_task_id等一些字段,has_handler用于当Promise最终为rejected时判断是否存在rejected回调并打印错误提示信息,另外两个字段个人还没有发现是什么作用
实现fulfill、resolve和reject方法,fulfill为最终resolve过程,传入非thenable的值并执行回调,与reject相同;resolve方法调用上面的resolvePromise处理可能为thenable的传入值,resolve和reject方法都只在pending状态时执行(Promise的状态只能改变一次,当Promise完成之后,状态不可改变)
1 | /** |
4.2.then方法,由于ES6中的class仅为语法糖,所以在类内部定义的非静态方法均会被添加到类的原型上,then方法的返回值为另一个promise以支持链式调用,对于不同的状态,then方法中的执行过程不同
当处于pending状态时,向原promise的reactions链表中添加新的reaction,此处调用的resolve和reject函数为新promise的resolve和reject函数,实现了promise的状态传递
当处于fulfilled或rejected状态时,直接将回调函数放入微任务执行
1 | /** |
4.3.catch方法,实为then方法的语法糖
1 | /** |
4.4.静态的resolve和reject方法
1 | /** |
4.5.Promise/A+测试所需的代码,promises-aplus-tests
中规定的需要在adapter上定义一个deferred属性返回一个对象,对象上包含promise、resolve、reject属性
1 | SelfPromise.deferred = function () { |
最后
本人才疏学浅,若有错漏,望不吝赐教😃