手写promise没你想象中那么难(上)

269 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

前言

大家好,我是除了开发,什么都想试试的布布。目前Promise 是 JavaScript 异步编程的一种流行解决方案,那理解promise原理早该提上日程了。理解原理?除了原生手写一个promise库,还能有什么更好的解决办法吗?

Promise 类

Promise 的构造函数必须接收一个函数参数(也就是需要执行异步任务的函数),该函数将在传入以后立即调用,并传入 Promise 对象下的两个方法 resolvereject

Promise 状态

  • 每一个 Promise 对象都存在以下三种状态:

    • PENDING : 进行中,Promise 对象的初始状态
    • FULFILLED : 已成功
    • REJECTED : 已失败

每一个 Promise 对象只能由 PENDING 状态变成 FULFILLEDREJECTED,且状态发生变化以后就不能再改变了

一个 Promise 对象状态的变化并不由 Promise 对象本身来决定,而应该是由我们传入的异步任务完成情况来决定的,Promise 提供了两个用来改变状态的方法

promise.#resolve 方法

Promise 对象的状态从 PENDING 变为 FULFILLED,并执行成功后的注册任务

注意:如果当前状态已经改变过了,则直接 return

promise.#reject 方法

Promise 对象的状态从 PENDING 变为 REJECTED,并执行失败后的注册任务

注意:如果当前状态已经改变过了,则直接 return

实现promise

注意:由于篇幅有限,以下实现promise未写原代码比对。

实现promise的三种状态

image.png

实现then的问题

  1. 多个then(注意用数组保存且执行,避免只返回最后一个值,出现覆盖问题);
  2. 链式操作;
  3. then的返还值处理;
  4. 微任务宏任务问题

image.png

image.png 上面代码的结果受执行顺序的影响

image.png

为什么会出现上面的情况呢?这其实跟同步异步,微任务宏任务有必然的联系。我们对上面自己封装的promise进行一下异步操作,即将promise的两个方法最后run函数调用换成setTimeout(run) 异步调用即可。改完后顺序问题解决了,但又出现了其他问题。

先想一下下面代码按照自己封装的promise运行的结果:

image.png

但是按照原promise进行运行后,同样的代码得出的结果如下图:

image.png 对比之后发现,对于同步执行的代码,结果是相同的,但对于异步执行的代码,返回结果的顺序是不同的。这就反映出宏任务微任务的问题。

  • 异步任务:
    • 微任务:一个需要异步执行的函数,执行时机是在主函数执行结束之后、当前宏任务执行之前。
    • 宏任务:宏任务的时间颗粒比较大,执行的时间间隔是不能精确控制的,对一些高实时性的需求就不太符合。
    • .then方法是一个微任务

想要解决宏任务微任务的问题就要用到MutationObserver构造函数进行监听操作,将then方法改成微任务。后续有时间在写一片关于MutationObserver讲解的文章吧。

image.png

image.png

实现then的链式调用及返回值问题。改造then方法:

image.png

周边方法

  1. 原型方法 catch 、finally
  2. 静态方法 race all allSettled resolve reject 写不完了,休息、休息一下。周边方法请看下一期!!!