javaScript 进阶之路 --- 《手写 Promise(中篇)》(二)

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

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


我们现在要明确一点,我们上面的代码 resolve 到底被调用了吗?会不会压根就是 resolve 没被调用才导致现在 then 拿不到数据呢?

我们在 resolve 里加一句打印,我们看看到底是不是这个原因。

image.png

在控制台可以清楚的看到,虽然没有第一时间执行,但是我们的 resolve 是确确实实执行了的。

70f5d4e4bd3e490186c0c3283ebbb0ea_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.jpg

清楚了这一点,我们需要理清楚思路。既然你 resolve 是在一秒后才会执行。如果我是 then 函数我可能会这样想:“resolve 函数啊,如果你执行完毕了以后你再通知我该有多好啊,别让我一个人先走一步~”

顺着这个思路,我们就要在 resolve 这里构思有什么方法可以去通知 then

image.png

这里我们再想想,我们的数据是在哪读取的?

image.png

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

image.png

这样我 then 函数坐享其成不是更美吗?

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

image.png

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

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

image.png

它用来干嘛呢?我们稍后揭秘,我想现在你的代码应该是下面这样子。

image.png

四. 神奇的回调函数


我们由上面可知,我们主要是因为 then 方法在 state==='pending' 的时候,没办法做任何操作才无法拿到异步函数传递过来的数据的。

image.png

注意接下来是全文重点: 当我在 state==='pending' 的时候,我把刚刚定义好的 callBackFn 函数值设置为 thenonFulfilled 回调函数的值。

image.png

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

别着急,我们先试一下行不行再一步一步解释原因。还是之前的代码,按照下面代码的逻辑,我们应该会在两秒以后看到控制台输出 看看行不行 这个字符串。

image.png

我们看一下效果:

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

什么情况,还真可以!!

不要觉得这是什么黑魔法,其实思路特别特别简单。顺着之前的思路,当我们的代码执行以后。首先会执行。

image.png

我们的 resolve 就被丢进了 宏任务队列里去了。

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

image.png

接下来我们就有需要跳到 MyPromise 类中去看 then 函数调用后发生的情况。首先我们非常明确的是,这时候由于 resolve 还没执行,所以我们的 state 还是 pending 状态。

image.png

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

image.png

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

至此,任何其他事情还没发生,然后我们静等了两秒以后,resolve 函数从任务队列里被推进了主线程。我们需要转头去看 resolve 函数执行。

image.png

我们可以非常非常清晰的看到,谁在最后执行了?没错!!就是我们两秒之前 被赋值为 onFulfilled 函数的 callBackFn 函数!!!

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

image.png

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

五. 修复 bug


但是现在我们又产生了一个新的问题,当我们的 resolve 又变成了同步赋值的时候,我们看看是什么后果。

image.png

看一下控制台输出什么?

image.png什么情况?我们的 callBacnFn 又不是一个 function了?

你需要清晰的知道,如果我们的 resolve 没有放进 setTimeout 里的执行的话,它就是一个同步代码,同步代码的话,它就会在 then 函数执行之前执行。

image.png

反应在 MyPromise 类里面的执行过程就是。我们的 callBacnFn 在被赋值之前就被调用了,那肯定会报错啊,因为我们既没有给它赋初始值,又没有被 then 函数调用,所以它现在就是 undefined

image.png

那怎么办呢?其实非常非常简单,我们只需要在执行 callBackFn 之前,判断一下它存在不存在就可以了。

image.png

由于是教学,我们写一种更加容易理解的代码,如果有我就执行,如果没有我就不执行,就是这么简单。

image.png

我们看一下控制台输出还有问题吗:

image.png

ok,没问题了~

结语:


至此距离我们完成自己的 MyPromise 类已经成功了一大半!我相信通过消化这一篇的内容,你会收获很多很多额外的知识。是不是有一种原来 Promise 不过如此的感觉~

其实有很多很多东西都是用很基本的函数,通过很巧妙的设计去完成一些看起来很复杂的逻辑。在下一章我们会迎来最后的几个关键点,如:微任务的创建then函数的链式调用,希望你能坚持下去。🎁

如果你暂时还没读懂,没关系,我建议你先去看一下我们上面的几个支线任务 再回过头细细品味本篇内容。距离我们手撕 Promise 已经近在咫尺了,你的登神长阶完成了几章呢?加油,一起进步呀!冲鸭~

相关文章
|
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
下一篇
无影云桌面