javaScript 进阶之路 --- 《手写 Promise(后篇)》(一)

简介: javaScript 进阶之路 --- 《手写 Promise(后篇)》

image.png

手写 Promise(后篇)


前言: 最后的章节终于要来了,不知道有没有人真正跟进下去这个进阶系列。最初我的本意只是想直接从 《手撕 Promise》 开始。但是我想了想,这样的话对一些基础知识不是特别牢固的小伙伴不太友好,于是就创建了该专栏尽量从头开始讲给那些真正想从我的博文中学习到那么一丢丢东西的人。一起加油吧,冲鸭~

阅读本文前需要拥有我们前面的六个进阶任务的通关钥匙🔑 (0/6)

请跟随本文完成你登神长阶的最后一步。

一. 分析 MyPromise 现有的问题


如果你跟进了前篇的知识,那么你目前的代码应该是下面这个样子。

image.png

虽然看起来即实现了存储同步数据的功能,又实现了存储异步数据的功能,但是到目前为止,我们的 MyPromise 还是一个假的 Promise 。什么意思呢?

我们先看一下原生的 Promise 存储一个同步数据时的样子。

image.png

根据之前的知识,在主线程的 console.log('我在主线程,我应该是第一执行') 肯定是会比 Promise 实例的 then 方法的 console.log 执行的快的,因为一个是在主线程,一个还得在微任务队列里排一会队。我们可以很快得出,在控制台的结果应该如下:

image.png

现在我们测试一下我们的刚刚写好的 MyPromise 的情况是什么样子的。如果我们的 MyPromise 是理想状态下的效果, resolve 方法应该会被放入微任务队列。所以下面的代码按照理想情况应该是先输出 console.log(我应该是第一次执行) 这行代码,然后输出数字 1

image.png

然而结果却是:

image.png

这该怎么办呢?🤔

二. 微任务的创建


如果你之前认真读过我的《宏任务和微任务》这篇文章,那么你一定知道创建一个微任务其实非常非常简单。没错,就是使用 window 对象身上的 queueMicrotask 函数。

说干就干,我们的数据是在哪读的?你还记得吗?没记起来我提醒你一下,应该是在 then 方法的第一个回调函数 onFulfilled 函数中的吧?那不就非常简单了吗?

image.png

我直接在 state==='fulfilled' 的时候,也就是数据填充好以后,我将 onFulFilled 函数从原来的同步执行代码逻辑转变为放入微任务队列去执行。哦哦,对了,别忘了我们 resolve 函数也执行了一个特殊的 onFulfilled 函数。

image.png

那么这里同理,把读取数据的任务放入微任务队列里去执行。

image.png

这时候我们测试一下,看看是不是我们想的那样。

image.png

59fed59351c24d6db29906a8b191b435_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.jpg

上面是保存同步数据的情况,我们再测试一下保存异步数据的情况。

image.png

下面是控制台输出结果:

f9ac819067c34f03831892a139440dac_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.jpg

  1. 完美!是我们想达到的效果~

三. 多次调用then方法的结果


  1. 看似目前我们这个 MyPromise 好像有那味儿了。但是我们分析一下下面的一种情况。我们还是根据原生 Promise 来推断。
  2. 注意! 这里不是 then 方法的链式调用,而是一个 Promise 实例多次调用 then 方法的写法。(这里不要和链式调用搞混了)

image.png

让我们看一下控制台的情况:

a8f74d436ef84620802e3264f1acdb93_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.jpg

可以看到,我们执行了三次 then 方法,它就帮我们执行三次读取数据的操作。然而反过头来看一下我们的 MyPromise 是什么行为。

按照我们理想的效果,控制台应该会在2秒后输出三个 我是 MyPromise

image.png

ok我们测试一下:

5a12a1e9cf9e48c6a72abd27b4ac4cd8_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.jpg

可以看到,我们的控制台在2秒后只输出了一次 MyPromise。这是怎么回事呢?🤔

四. 分析 Bug 产生的原因


不着急,我们一步一步分析代码的执行顺序。首先会执行 MyPromiseexecutor 函数的代码。

image.png

然后代码会执行到 setTimout ,然后会把 resolve 放入宏任务队列里去等待2秒。

image.png

ok,接下来该执行下面三个连续的 then 方法。

image.png

注意接下来是全文第一个重点: 关键点就在于我们三个 then 是同步代码,一定要搞清楚这回事。明白了这一点,我们就需要去看 MyPromise 类里到底发生了什么情况。

由于我们的 resolve 还在任务队列里排着队,那么在两秒内这时候的 state 百分之一百还是 pending 状态。

image.png

可以我们的 then 是要继续走的啊,这里需要接着往下我们看 then 方法里的逻辑。由于我们这时候的 state==='pending' 所以下面的逻辑我们压根不用考虑,只需要考虑第一个 if 语句里的代码即可。

image.png

关键点就在于这里这段代码。

image.png

我执行的三次 then 在这里相当于执行了三次赋值操作。什么意思呢?

image.png

没看懂?没关系,我接下来这种写法你一定可以看明白什么意思。

image.png

你觉得控制台会为你分别执行三次吗?

image.png

看懂了这个例子,其实你就明白为什么我们的结果只会输出我们最后一次调用的 then 方法的结果了。因为们前面两次都被第三次所覆盖了。

image.png

所以我们才会看到下面个结果,只输出了一个 result3

76cf7a0f903749dba67d5a6622ac52ca_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.jpg

相关文章
|
12天前
|
前端开发 JavaScript
用JavaScript 实现一个简单的 Promise 并打印结果
用 JavaScript 实现一个简单的 Promise 并打印结果
|
12天前
|
JSON 前端开发 JavaScript
在 JavaScript 中,如何使用 Promise 处理异步操作?
通过以上方式,可以使用Promise来有效地处理各种异步操作,使异步代码更加清晰、易读和易于维护,避免了回调地狱的问题,提高了代码的质量和可维护性。
|
17天前
|
JSON 前端开发 JavaScript
浅谈JavaScript中的Promise、Async和Await
【10月更文挑战第30天】Promise、Async和Await是JavaScript中强大的异步编程工具,它们各自具有独特的优势和适用场景,开发者可以根据具体的项目需求和代码风格选择合适的方式来处理异步操作,从而编写出更加高效、可读和易于维护的JavaScript代码。
22 1
|
1月前
|
前端开发 JavaScript 开发者
JavaScript 中的异步编程:深入了解 Promise 和 async/await
【10月更文挑战第8天】JavaScript 中的异步编程:深入了解 Promise 和 async/await
|
1月前
|
前端开发 JavaScript 小程序
JavaScript的ES6中Promise的使用以及个人理解
JavaScript的ES6中Promise的使用以及个人理解
18 1
|
2月前
|
前端开发 JavaScript
JavaScript中的Promise:简化异步编程
JavaScript中的Promise:简化异步编程
|
2月前
|
Web App开发 前端开发 JavaScript
js之 Promise | 12-8
js之 Promise | 12-8
|
1月前
|
前端开发 JavaScript UED
深入了解JavaScript异步编程:回调、Promise与async/await
【10月更文挑战第11天】深入了解JavaScript异步编程:回调、Promise与async/await
15 0
|
2月前
|
前端开发 JavaScript
ES6新标准下JS异步编程Promise解读
ES6新标准下JS异步编程Promise解读
36 3
|
1月前
|
前端开发 JavaScript 开发者
深入理解JavaScript中的Promise:用法与最佳实践
【10月更文挑战第8天】深入理解JavaScript中的Promise:用法与最佳实践
58 0
下一篇
无影云桌面