实践了一个符合 Promise/A+ 规范的 repromise
Promise 札记
研究 Promise 的动机大体有以下几点:
对其 api 的不熟悉以及对实现机制的好奇;
很多库(比如 fetch)是基于 Promise 封装的,那么要了解这些库的前置条件得先熟悉 Promise;
要了解其它更为高级的异步操作得先熟悉 Promise;
基于这些目的,实践了一个符合 Promise/A+ 规范的 repromise
本札记系列总共三篇文章,作为之前的文章 Node.js 异步异闻录 的拆分和矫正。
Promise/A+ 核心
在实现一个符合 Promise/A+ 规范的 promise 之前,先了解下 Promise/A+ 核心,想更全面地了解可以阅读 Promise/A+规范
- Promise 操作只会处在 3 种状态的一种:未完成态(pending)、完成态(resolved) 和失败态(rejected);
- Promise 的状态只会出现从未完成态向完成态或失败态转化;
- Promise 的状态一旦转化,将不能被更改;
repromise api 食用手册
Promise.resolve()
Promise.resolve() 括号内有 4 种情况
1 | /* 跟 Promise 对象 */ |
Promise.reject()
相较于 Promise.resolve(),Promise.reject() 原封不动地返回参数值
Promise.all(arr)
对于 Promise.all(arr) 来说,在参数数组中所有元素都变为决定态后,然后才返回新的 promise。
1 | // 以下 demo,请求两个 url,当两个异步请求返还结果后,再请求第三个 url |
Promise.race(arr)
对于 Promise.race(arr) 来说,只要参数数组有一个元素变为决定态,便返回新的 promise。
1 | // race 译为竞争,同样是请求两个 url,当且仅当一个请求返还结果后,就请求第三个 url |
Promise.wrap(fn) —— 回调函数转 Promise
通过下面这个案例,提供回调函数 Promise 化的思路。
1 | function foo(a, b, cb) { |
如上是一个传统回调函数使用案例,只要使用 Promise.wrap() 包裹 foo 函数就对其完成了 promise 化,使用如下:
1 | const promiseFoo = Promise.wrap(foo) |
Promise.wrap 的实现逻辑也顺带列出来了:
1 | Promise.wrap = function(fn) { |
then/catch/done
这几个 api 比较简单,合起来一起带过
1 | Promise.resolve(1) |
实践过程总结
坑点 1:事件循环
事件循环:同步队列执行完后,在指定时间后再执行异步队列的内容。
之所以要单列事件循环,因为代码的执行顺序与其息息相关,此处用 setTimeout 来模拟事件循环;
下面代码片段中,① 处执行完并不会马上执行 setTimeout() 中的代码(③),而是此时有多少次 then 的调用,就会重新进入 ② 处多少次后,再进入 ③
1 | excuteAsyncCallback(callback, value) { |
坑点 2:this 的指向问题
this.callbackArr.push() 中的 this 指向的是 ‘上一个’ promise,所以类 CallbackItem 中,this.promise 存储的是’下一个’ promise(then 对象)。
1 | class Promise { |
more
实践的更多过程可以参考测试用例。有好的意见欢迎交流。