关于javascript:手写-Promise中篇

前言: 浏览前须要领有咱们后面的五个干线工作的通关钥匙🔑 (0/5),

  • JS 代码运行机制
  • 加深了解回调函数
  • 手写“回调天堂”
  • 宏工作和微工作
  • 手写 Promise(前篇)

请实现你的登神长阶

本文紧接着前篇的主线工作,倡议没看《前篇》的小伙伴先去看一下《前篇》再回过头看本篇内容。(没浏览过后面文章的小伙伴,倡议在父母的陪同下实现浏览。📖)


一. 思考 MyPromise 现有的问题

  1. 如果你跟进了之前的文章,那么上面应该是你目前的代码
  2. 尽管当初如同咱们的逻辑都在顺着一步一步走,然而这外面其实有一个十分重大的 bug 。咱们临时先不揭秘,反过来咱们先思考一下🤔,在原生的 Promise 如果咱们在结构器函数内屡次调用 resolve 函数的话,它保留的值是会以哪次为准呢?

    这里咱们间接揭晓答案。后果是 Promise实例 只会保留第一次调用 resolve 函数保留的那个数据。

  3. 然而当初反过头来看看咱们目前的逻辑。

    在控制台输入的后果是:

    造成这种状况的起因非常简单,因为依照下面的写法,咱们相当于在 executor 里间断调用了三次 resolve 如下所示:

    后果不言而喻,它调用了三次,依照代码逻辑,它 result 前两次的值被笼罩了,它保留了最初一次调用 resolve 时存入的值。

  4. 这里的解决办法仍旧非常简单,咱们不须要借助其它货色,我想你也能大略猜出来。这里还是须要借助 #state 来判断咱们是否继续执行过了 resolve

    别忘了,咱们在 constructor 刚刚执行的时候最先批改的就是 #state 的值,所以咱们只须要在 resolvereject 函数执行之前,先判断以后 #state 是否不是 pending,如果不为 pendng 则阐明之前曾经执行过了,则间接返回,不进行任何其余操作。 reject 同理。咱们再看一下控制台当初的的样子。

    嗯,当初的确不会再执行前面的 resolve 函数了。

二. 异步数据的存储

  1. 写到这里你可能会发现,咱们当初的 MyPromise 其实是一个假的,是一个只能保留同步数据的一般类而已。
  2. 因为咱们当初的 Promise 是不能读取到异步存储到数据的。 这也是 Promise 的外围性能 保留异步数据 。因为咱们向后端申请数据相对不是一瞬间数据就过去的,而是会有工夫的提早,过一段时间才须要调用 resolve 去保留。
  3. 什么意思呢?咱们先看原生的 Promise 如果应用异步代码执行 resolve 的话是什么状况。 咱们在 executor 函数体内开启一个定时器,在一秒当前去执行 resolve 保留数据。

    咱们在控制台看一下输入后果:

    能够分明的看到,咱们在 then 办法过了一秒,胜利读取到了 result 中的数据。

  4. 当初咱们回过头看看咱们的 MyPromise 是什么成果。

    察看下面的代码,咱们推算出在现实状态,控制台会输出一个数字 1。然而后果的确—控制台空洞无物。

    这是怎么回事呢?咱们一步一步剖析。

  5. 当咱们的代码执行时,首先会去执行这一段代码。
  6. 依据后面的常识能够得出,咱们的 executor 函数会马上开始执行。

    紧接着就遇到 setTimeout 函数。通过后面的学习,咱们晓得 setTimeout 的回调函数会被放进宏工作队列,后果就是咱们的 resolve 被放进了宏工作队列去乖乖排队去了,

  7. 依据从上往下的执行程序,马上就会去执行 then 办法。
  8. 留神: 这时候咱们须要去看 MyPromise 类里的执行状况,能力晓得起因

    当咱们的 executor 执行后,咱们的 this.resolve 会在一秒后才会执行,所以 state 的状态还是 pending。 而此时咱们的 then 又是在主线程执行的代码。所以自然而然,then 函数不会有任何后果。

  9. 本着谨严的态度,咱们进一步验证一下咱们的推断是不是正确的。让咱们在 then 办法执行的时候打印一下 this.state

    看一下控制台:

    果然是这个起因,那当初怎么办呢?🤔

三. 构思异步存储数据的思路

  1. 咱们当初要明确一点,咱们下面的代码 resolve 到底被调用了吗?会不会压根就是 resolve 没被调用才导致当初 then 拿不到数据呢?
  2. 咱们在 resolve 里加一句打印,咱们看看到底是不是这个起因。
  3. 在控制台能够分明的看到,尽管没有第一工夫执行,然而咱们的 resolve 是确确实实执行了的。
  4. 分明了这一点,咱们须要理分明思路。既然你 resolve 是在一秒后才会执行。如果我是 then 函数我可能会这样想:“resolve 函数啊,如果你执行结束了当前你再告诉我该有多好啊,别让我一个人先走一步~”
  5. 顺着这个思路,咱们就要在 resolve 这里构思有什么办法能够去告诉 then
  6. 这里咱们再想想,咱们的数据是在哪读取的?

    没错,是在 then 函数的第一个回调函数 onFulfilled 里去读取的。那么有没有一种可能,我让你 resolve 去帮我执行这个 onFulfilled 函数不就更省心了吗?

    这样我 then 函数不劳而获不是更美吗?

  7. 那么问题来了, then 函数的回调函数其实只能在 then 的作用域去调用,什么意思呢?咱们给函数定义参数的时候,实际上是执行了上面的形参实参从新赋值的操作。所以咱们的参数对外是压根看不见的。

    换而言之,resolve 函数压根就不晓得有 onFulfilled 这个函数!!!。

  8. 这就麻烦了,这怎么办呢?别急咱们再定义一个变量,叫做 callBackFn,这个变量也是一个函数。

    它用来干嘛呢?咱们稍后揭秘,我想当初你的代码应该是上面这样子。

四. 神奇的回调函数

  1. 咱们由下面可知,咱们次要是因为 then 办法在 state==='pending' 的时候,没方法做任何操作才无奈拿到异步函数传递过去的数据的。
  2. 留神接下来是全文重点: 当我在 state==='pending' 的时候,我把刚刚定义好的 callBackFn 函数值设置为 thenonFulfilled 回调函数的值。

    接下来就是最神奇的一步操作,我再把 callBackFn 放到 resolve 函数拿到数据之后执行!

    别着急,咱们先试一下行不行再一步一步解释起因。还是之前的代码,依照上面代码的逻辑,咱们应该会在两秒当前看到控制台输入 看看行不行 这个字符串。

    咱们看一下成果:
    什么状况,还真能够!!

  3. 不要感觉这是什么黑魔法,其实思路特地特地简略。顺着之前的思路,当咱们的代码执行当前。首先会执行。

    咱们的 resolve 就被丢进了 宏工作队列里去了。

4.而后主线程持续往下走,就走到了 then 函数中。

接下来咱们就有须要跳到 MyPromise 类中去看 then 函数调用后产生的状况。首先咱们十分明确的是,这时候因为 resolve 还没执行,所以咱们的 state 还是 pending 状态。

那么这时候就会走 then 函数的第一个判断逻辑。

它会将咱们 then 函数的第一个参数 onFulfilled 赋值给咱们之前定义好的 callBackFn 变量。

  1. 至此,任何其余事件还没产生,而后咱们静等了两秒当前,resolve 函数从工作队列里被推动了主线程。咱们须要转头去看 resolve 函数执行。

    咱们能够十分十分清晰的看到,谁在最初执行了?没错!!就是咱们两秒之前 被赋值为 onFulfilled 函数的 callBackFn 函数!!!

  2. 千万不要迷,这里完完全全就等价于两秒后 resolve 函数帮我去调了 then 函数的 onfulfilled 函数。

    只不过咱们没有方法间接去调用定义在 then 函数作用域的那个 onFulfilled ,而是通过了一个两头变量的模式,“间接去调用了它”。这便是 JS 回调函数的魅力所在。

五. 修复 bug

  1. 然而当初咱们又产生了一个新的问题,当咱们的 resolve 又变成了同步赋值的时候,咱们看看是什么结果。

    看一下控制台输入什么?

  2. 什么状况?咱们的 callBacnFn 又不是一个 function了?
  3. 你须要清晰的晓得,如果咱们的 resolve 没有放进 setTimeout 里的执行的话,它就是一个同步代码,同步代码的话,它就会在 then 函数执行之前执行。
  4. 反馈在 MyPromise 类外面的执行过程就是。咱们的 callBacnFn 在被赋值之前就被调用了,那必定会报错啊,因为咱们既没有给它赋初始值,又没有被 then 函数调用,所以它当初就是 undefined
  5. 那怎么办呢?其实十分非常简单,咱们只须要在执行 callBackFn 之前,判断一下它存在不存在就能够了。

    因为是教学,咱们写一种更加容易了解的代码,如果有我就执行,如果没有我就不执行,就是这么简略。

    咱们看一下控制台输入还有问题吗:

    ok,没问题了~

结语:

至此间隔咱们实现本人的 MyPromise 类曾经胜利了一大半!我置信通过消化这一篇的内容,你会播种很多很多额定的常识。是不是有一种原来 Promise 不过如此的感觉~

其实有很多很多货色都是用很根本的函数,通过很奇妙的设计去实现一些看起来很简单的逻辑。在下一章咱们会迎来最初的几个关键点,如:微工作的创立then 函数的链式调用,心愿你能坚持下去。🎁

如果你临时还没读懂,没关系,我倡议你先去看一下咱们下面的几个干线工作 再回过头细细品味本篇内容。间隔咱们手撕 Promise 曾经近在眉睫了,你的登神长阶实现了几章呢?加油,一起提高呀!冲鸭~

【腾讯云】轻量 2核2G4M,首年65元

阿里云限时活动-云数据库 RDS MySQL  1核2G配置 1.88/月 速抢

本文由乐趣区整理发布,转载请注明出处,谢谢。

您可能还喜欢...

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据