前端入门20-JavaScript进阶之异步回调的执行时机 (3)

如果当程序卡在 alert("3"),异步请求结果回来了,这时候还没有取消 alert 弹窗,或者一取消的时候,就先输出 success,再输出 3.1,则表示,回调任务的代码块是被安排到发起异步请求的这个 <script> 里代码都执行结束就去处理。

如果 success 是在 3.1 之后才输出,那么,就可以说明,浏览器处理 js 代码,是以 <script> 作为事件粒度,放入事件循环队列中去处理。看看日志:

前端入门20-JavaScript进阶之异步回调的执行时机

好了,现在可以确认了,success 是在 3.1 之后才输出的,那么来整理下结论吧。

结论

看到这里的话,你一定要继续看最后的一小节的内容,一定!

之后问了一些前端同学,然后我基于对 Android 那边的类似理解,我自行梳理了下面的这些结论,因为涉及底层运行机制、浏览器行为的这些知识我还没开始去看,所以下面结论不保证正确,只能说是,基于我目前的能力,针对于做实验所得到的现象,我梳理出一些可以解释得通的结论。

浏览器解析 html 文档时,是按顺序一行一行进行解析,当处理到 <script> 标签时,会暂停当前页面的渲染,进入 js 代码的执行。

在执行当前 <script> 标签内的代码时,是以整个标签内的代码块作为事件粒度,放入事件队列中进行处理。

如果在当前 <script> 标签里的代码发起了某些异步工作,如异步网络请求,并设置了回调,那么回调任务的代码块会被单独作为一个事件,等到异步工作结束后,插入当前事件队列中。

所以,如果回调任务在执行当前 <script> 标签内的代码时就已经加入队列了,那么等到当前 <script> 里的代码都执行结束后,就可以轮到回调任务的执行。

如果回调任务直到当前 <script> 里的代码都执行结束也还没被加入事件队列,那么这时浏览器会接着去解析 html 文档,如果又碰到下个 <script> 标签,那么会将这个 <script> 标签内的代码块放入事件队列中处理。

所以,如果这时候第一个 <script> 标签内的代码发起的异步任务才结束,才将回调工作加入事件队列中,那么这个回调工作的代码只能等到第二个 <script> 标签内的代码都执行结束后才会被处理。

碰到的问题

为啥会想要梳理这个结论呢,是因为我碰到这么一种场景:

<script type="text/javascript"> document.location.href = "http://www.baidu.com" //... </script>

之前有个 h5 项目中,有类似的代码,就是满足一定条件下,需要将页面跳转至其他页面。

修改 location.href 貌似不是同步操作,我猜测应该是这行跳转代码会告诉浏览器,当前页面准备跳转,这时候,浏览器再生成一个跳转事件,接入事件队列中等待执行的吧。

因为,最初我以为这是个同步操作,所以我认为当程序执行到 document.location.href = xx 这行代码之后,页面就会发生跳转,然后这行代码下面的那些代码都不会被执行,但最后实际运行时,却发现,这行代码下面的代码也都被执行了。

后来经过测试,发现,跳转语句这行代码所在的 <script> 里的代码会被全部执行完,然后才发起页面跳转,下个 <script> 里的代码不会被执行,所以,那个时候,就有个疑惑了,在 js 中发起一个异步操作的话,这个异步工作的回调任务的执行时机到底在哪里?

后来稍微查了相关资料,发现了个词说 JavaScript 是单线程机制,联想到 Android 中的主线程消息循环机制,这才想来理一理。

卧槽

卧槽,卧槽,卧槽~

不要怪我连骂粗话,这篇文章是挺早之前就写好的了,只是一直还没发表,待在草稿箱中。而最后这一小节,是等到我差不多要发表时才新增的内容。

为什么要骂粗话,因为我发现,我上面所梳理的结论,好像全部都是错误的了,但也不能说全部错误,我实在不想把辛辛苦苦写好的都删掉,也不想直接就发出来误导大伙,所以我在最后加了这一小节,来说明情况,大伙看这篇的结论时,看看就好,讨论讨论一下就好,不要太当真哈。

事情是这样的,我一些前端同学觉得我的理解有误,所以尝试将我上文中的例子在他的电脑上运行测试了下,结果你们看一下:

前端入门20-JavaScript进阶之异步回调的执行时机

这是对应上文中第一个测试,即让程序卡在 alert("2") 这里,然后等到请求结果回来后,取消 alert 弹窗,这种场景,按照我们上面梳理的结论,回调任务在当前 <script> 执行结束之前就被插入事件队列中了,所以回调任务应该会在第二个 <script> 代码之前先被处理,但我同学的情况却是,回调任务等到所有 <script> 都处理完才被执行???

一脸懵逼???

然后,我怀疑是不是不同浏览器会有不同的行为,所以同样的测试步骤我在 IE 浏览器上测试了一下:

前端入门20-JavaScript进阶之异步回调的执行时机

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyyxfd.html