看了好几篇别人的博客, 才把大概的原理搞清楚…
其实异步思想算是好理解, 但是代码现实也是够麻烦的
参考这两个实现:
https://github.com/xieranmaya/blog/issues/3
https://github.com/bruce-xu/Promise/blob/master/Promise.js
一.结构
构造函数
在 promise 对象中增加分别代表成功回调和失败回调的两个数组,数组中的每一项是通过内部封装的闭包函数调用的结果,也是一个函数。
不过这个函数可以访问到内部调用闭包时传递的 promise 对象,因此通过这种方式也可以访问到我们需要的下一个 promise 以及其关联的成功、失败回调的引用
resolve/reject
我们使用 promise,是期望在未来的某个时刻能获得一个结果,并且可用于接下来的 promise 调用。
所以resolve函数需要有一个参数来接收结果(同样,promise 执行失败后,我们也希望在后续 promise 中获得此失败信息,做相应处理。所以reject函数也需要有一个参数来接收错误)。
|
|
二.then方法
Promise 代表着一个承诺。作为承诺,总需要有一个结果,无论成功与否。如果成功,我们会获得需要的结果;当然也有可能会失败。
then方法接收两个参数:onResolve和onReject,分别代表当前 promise 对象在成功或失败时,接下来需要做的操作。
比如形如promise.then().then()…。为了方便链式调用,then方法的实现中,都会返回一个新的 promise 对象,在then方法中增加闭包调用以及为前一个 promise 对象保存引用
|
|
此处then方法内创建的 promise 对象和暴露给用户直接调用的 Promise 构造函数所创建的 promise 对象有些不同。
用户调用 Promise 构造函数时需要传递resolver参数代表与此 promise 对象关联的任务,且任务会立即执行。
由此可知以下两点:
1.首先then方法中创建的 promise 关联的任务不能在 promise 对象创建时立即执行,所以先传入一个空函数以符合 Promise 构造函数调用格式;
2.其次前一个 promise 对象需要能够知道下一个 promise 对象是谁,其关联的任务是什么,这样才能在自己完成后调用下一个 promise 的任务。
因此前一个 promise 需要持有下一个 promise 以及其任务的引用。
由于 promise 的执行可能会成功也可能会失败,因此后一个 promise 一般会提供成功或失败后需要执行的任务供前一个 promise 调用。
三.回调
执行回调
resolve和reject函数中首先判断了当前 promise 的状态,如果不是pending(即已经被 resolve 或 reject 过了,不再重复执行)
然后赋予 promise 新的状态,并保存成功或失败的值。最后调用run函数。run函数用于触发接下来的 promise 的执行。run函数中需要注意的一点是,需要异步执行相关的回调函数。
|
|
保存之前状态的callback
由于成功回调onResolve和失败回调onReject都通过此闭包封装,所以在闭包中增加了第三个参数action,以区分是哪种回调。
|
|
四.done
done(或者fail或catch)就是then的语法糖
五.小结
小结一下:
Promise的主要思想就是用闭包把异步的操作保存下来, 然后通过多个Promise串联 依次调用(所以每个then必须返回一个新的Promise对象)
大概流程就是:
Promise构造函数(初始化状态等) -> resolve方法(改状态) -> run方法(setTimeout(0)加入js队列) -> 后续then()循环… -> js队列开始依次执行setTimeout(0)的回调
至此一个then完事了,但是这个then里如果有新的Promise对象, 就又续上了. 所以就是 重复 或者完成了
巧妙也是麻烦之处就是一个Promise对象, 能完成上述的循环
|
|