您的位置 首页 java

这一次,彻底理解Promise源码思想

关于Promise的源码实现,网上有太多答案,我也看过很多资料,但都不是很明白。直到有一天我学完 函数式编程 之函子的概念,才对Promise源码有了更深刻的认识。今天,就让我们来重新认识一下Promise。

我们知道,Promise的诞生是为了解决“回调地狱”的问题,它用同步链式的方式去解决异步的嵌套回调。

啥?同步链式?这不就是我们上一节学习的函子的思想吗?如果对函子有所了解,那么再来学习Promise源码就比较容易理解了。接下来,我们探究一下函子和Promise有着怎样的关系。

实现一个简单的Promise函子

先来回顾一下函子Functor的链式调用:

这一次,彻底理解Promise源码思想

函子的核心就是: 每个函子Functor都是一个新的对象 ,这个对象的原型链上有 map 函数。通过 map 中传递进去的函数fn去处理函子保存的数据,用得到的值去生成新的函子。

等等…函子是同步链式,而Promise是异步链式。 也就是说上面a的值是异步产生的,那我们该何如传入 this.value 值呢?

我们模拟一下通过 setTimeout500 毫秒后拿到数据100。其实也很简单,我们可以传进去一个 resolve 回调函数 去处理这个数据。

解释一下上面的代码:我们将 executor 传入并立即执行,在 resolve 回调函数中我们能够拿到 value 值,我们定义 resolve 回调函数将 value 的值赋给 this.value。

这样我们就轻松的完成了 a 这个对象的赋值。由于是异步得到的,那么我们怎么用方法去处理这个数据呢?

根据函子的思想, 在拿到数据之后,我们应该让 map 里传入的 fn 函数去处理数据。由于是异步处理, resolve 执行后才拿到数据,所以我们定义了一个 callback 函数,在 callback 里面执行 fn。最后把 fn 处理的结果交给下一个函子的 resolve 保存。

同时调用同一个Promise函子

Promise除了能链式调用,还能同时调用,比如:

像上面这个同时调用a这个函子。你会发现,它实际上只执行了c。原因也很简单,b先给a的 callback 赋值,然后c又给a的 callback 赋值。所以把b给覆盖掉了就不会执行啦。解决这个问题很简单,我们只需要让callback变成一个数组就解决了。

我们定义了callbacks数组,每次的调用a的then方法时。都将其存到callbacks数组中。
当回调函数拿到值时,在resolve中遍历执行每个函数。
如果callbacks是空, forEach 就不会执行,这也解决了之前把错的问题
然后我们进一步改了函子的名字为 MyPromise,将map改成then
简化了return中,let self = this;

增加reject回调函数

我们都知道,在异步调用的时候,我们往往不能拿到数据,返回一个错误的信息。这一小节,我们对错误进行处理。

其实很简单,就是我们就是在 executor 多传递进去一个 reject
根据异步执行的结果去判断执行 resolve,还是 reject
然后我们在 MyPromise 为 reject 定义出和 resolve 同样的方法
然后我们在 then 的时候应该传进去两个参数,fn,fn2

这时候将executor函数封装到asyncReadFile异步读取文件的函数

这就是我们平时封装异步Promise函数的过程,这个过程有没有觉得在哪见过。仔细看下,asyncReadFile 不就是前面我们提到的柯里化。

增加Promise状态

我们定义进行中的状态为pending
已成功执行后为fulfilled
失败为rejected

最后,现在来看传进去的方法 fn(this.value) ,我们需要用上篇讲的Maybe函子去过滤一下。

Maybe函子优化

Maybe函子很简单,对onResolved和onRejected进行一下过滤。

总结

Promise是一个很不好理解的概念,但总归核心思想还是函子。

同时,在函子的基础上增加了一些异步的实现。异步的实现是一个比较费脑细胞的点,把加粗的字体花点时间多思考思考,加油!

文章来源:智云一二三科技

文章标题:这一次,彻底理解Promise源码思想

文章地址:https://www.zhihuclub.com/180343.shtml

关于作者: 智云科技

热门文章

网站地图