1. Promise是啥?
Promise是异步编程的一个解决方案,相比传统的“回调函数”方法,使用Promise更为合理和强大,避免了回调函数之间的层层嵌套,也使得代码结构更为清晰,便于维护。
图:使用Promise避免"回调地狱"
2. Promise特性回顾
注:本文适用于有Promise基础并希望深入挖掘Promise特性的读者;如果想学习Promise基础,下面这两本书不错;
测试环境:
NodeJS:v8.11.1 babel-cli:6.26.0 babel-preset-env:1.6.1
下面借助几道与Promise相关的测试题
快速回顾其特性
题目1:
题目2:
题目3:
题目4:
题目5:
题目6:
题目7:
题目8:
题目9:
扫码获取exam01.js ~ exam09.js源码
3. 实现一版Promise试试!
Promise有很多社区规范,如 Promise/A、Promise/B、Promise/D 以及 Promise/A 的升级版 Promise/A+;Promise/A+ 是 ES6 Promises 的前身,而且网络上有很多可供学习、参考的开源实现(例如:Adehun、bluebird、Q、ypromise等)。
符合Promise/A+规范的一些开源实现: https://github.com/promises-aplus/promises-spec/blob/master/implementations.md
目标、资源
1.编写符合Promise/A+规范的RookiePromise
2. 通过Promise/A+规范测试集
Promise/A+规范文档: https://github.com/promises-aplus/promises-spec Promise/A+规范测试集: https://github.com/promises-aplus/promises-tests 符合Promise/A+规范的一些开源实现: https://github.com/promises-aplus/promises-spec/blob/master/implementations.md
接口分析
虽然一个Promise库的接口有很多
但只要我们识别出核心接口
其它接口均可由核心接口间接实现
A.第一步:先看看我们要实现哪些接口
可以看出,共需实现7个接口;
构造函数:RookiePromise; 成员函数:then、catch; 静态成员:resolve、reject、all、race;
B.第二步:识别核心接口
可以看出,7个接口中,只有构造函数RookiePromise和成员函数then算核心接口,其他接口均可通过这两个接口实现;
构造函数:RookiePromise; 成员函数:then、catch; 静态成员:resolve、reject、all、race;
开始编码
一定要多读几遍规范
不能放过规范中的任何细节
A.第一步:搭建RookiePromise主框架
B.第二步:编写状态转换函数
Promise 对象的状态改变,只有两种可能:pending -> fulfilled 和 pending -> rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果;
——《ES6 标准入门(第三版)》
注:_notify函数用作异步执行传入的函数数组以及参数;代码中将_callbacks、_errbacks传给_notify函数后立即清空,是为了保证_callbacks、_errbacks至多被执行一次;
C.第三步:实现then接口
D.第四步:实现resolve(promise, x)接口
至此,RookiePromise编码完成;
小结一下:
RookiePromise的结构是按照Promise/A+规范中对then、resolve接口的描述组织的;优点是编码过程直观,缺点是innerResolve函数篇幅太长、头重脚轻,不够和谐;扫描后面的二维码查看RookiePromise完整源码,相信各位可以写出更漂亮的版本;
测试
用Promise/A+的官方用例
测试RookiePromise的正确性
A.第1步:安装Promise/A+测试工具
npm install –save promises-aplus-tests 注:这里采用局部安装,后面需要通过npx命令执行;
B.第2步:编写RookiePromise的测试适配器
RookiePromise需要额外提供3个静态接口,供Promise/A+自动测试工具调用;
C.第3步:执行测试
npx promises-aplus-testsRookiePromiseTestAdapter.js > log.txt