自己撸一个Promise库的过程

Posted by ngtmuzi on 2017-01-19
班门弄斧

新年第一篇博客,写了一年多的JS,感觉只是弄懂了皮毛,没有好好的钻研过,关于前端那方面更是完全空白,看了别人的面试经历后深感忧虑。正好年前比较闲,重构的项目也基本稳定了,于是就无聊想研究下代码,Promise从ES6出来就用到现在,then/catch那一套倒是很熟了,但还是不清楚里面的原理,就趁此机会深入理解一下

参考资料:

Promises/A+规范
崔鹏飞的博客
Promise测试库

从我的结果来说,按照规范上的规则一行一行地写,配合测试库一遍一遍地跑,基本上都能完成代码,而且还有一种类似闯关的感觉(参见提交记录),挺爽,可以试试。

注意点

因为规范说得实在太够详细了,基本也没什么好介绍的了,说下一些需要注意的点吧:

  • 三个状态,运行中(pending),已完成(resolved),已失败(rejected)
  • 规范2.2.4onFulfilledonRejected在运行至上下文堆栈仅剩平台代码前不能运行;说得很绕,主要是指这2个函数需要异步执行(即使Promise已经resolved),而常用的异步执行函数就是setTimeoutsetImmediate以及node特有的process.nextTick等函数,具体函数的不同会影响到整个Promise执行的效率,这里可以关注一下
  • 规范2.2.6.1:当Promise进入完成状态,所有onFulfilled都需要按它们调用then的顺序来触发;这里隐含了一个点:then里传进去的函数是通过主动回调来触发的,也就是说Promise本质上是回调的封装,只是对状态和规范做了严格限制,使得最后使用的时候方便不少
  • 规范2.3:Promise解决程序,规范里将它表示为[[Resolve]](promise, x),实际上就是写一个函数,输入一个未完成的promise和值x,通过一系列规则判断,以确定这个promise最后的状态。这部分就是Promise规范的核心了,因为规则写得十分详细,照着来写基本都可以过,关注点:要保证自己传进x.then的函数仅能被调用一次,全程记得用try-catch包裹

这样基本就差不多了,从零写出来之后对Promise理解还是增加了不少的,之后可以尝试加入一些bluebird的常用方法,比如tryallmap之类的,对理解代码逻辑很有帮助。

附上我的Promise库。另外要说一句,多尝试new Promise()来自己封装异步代码,我是见过不少同事只懂从Promise.resolve()开始的,那就弄丢了Promise最强大的部分