理解JS异步操作

参考文章:

  1. 阮一峰ES5教程:异步操作 —— 理解异步操作的基本模式和控制流程,了解定时任务的实现,Promise的用法
  2. 前端需要了解的浏览器原理(占坑)
  3. Inside look at modern web browser (part 1) —— 该系列文章一共4节,详细介绍了浏览器的工作原理。建议先看part1,然后看过参考文章4后,还想要更加深入全面地了解浏览器再看part2-4。
  4. 浏览器的工作原理:新式网络浏览器幕后揭秘 —— HowBrowsersWork中译版,看完可了解浏览器的基本组件和呈现引擎的工作流程

 

最开始通过看ES5教程了解JS异步操作时,理解了JS的单线程模型和事件循环机制,教程中也介绍了实现JS异步操作的方法。但是我还是一头雾水,为什么需要异步操作?怎么划分异步操作和同步操作?应该在哪里进行异步操作?我脑中都是模糊的概念。后来我发现我就是少根筋,我只是需要了解一下异步操作的使用场景和通常的异步任务。

 

注意:JS层面的异步和操作系统层面的异步(涉及进程线程并发)是有所区别的,建议分开看待,不易混淆。

 

一、JS的单线程模型和事件循环机制

当我们谈论JS层面的异步时,不得不谈JS单线程模型和事件循环机制。这是JS异步概念的来源。

JS的单线程模型意味着,在执行JS时只有一个主线程,每个任务必须顺序执行。如果当前任务执行时间过长,会导致接下来的所有任务都处于阻塞状态,进而导致浏览器卡死等我们不希望看到的状况。为了解决这一问题,事件循环机制(Event Loop)被发明出来。

事件循环机制中,负责执行JS脚本的单线程我们称为主线程,在内存中表现为一个执行栈,JS只通过主线程执行任务。异步任务被挂起,存储在堆中,当异步任务准备就绪,它对应的事件便进入任务队列。主线程首先执行同步任务,然后查看任务队列是否有就绪的异步任务(或者时间到了的异步任务),调用相应的回调函数执行,直到任务队列为空。至此即完成一个事件循环。如下图所示。

                                                               

                                                          

 关于JS的事件循环机制更详细的资料可以参考MDNES5教程

 

 二、异步任务

异步任务指的是被JS引擎放在一边,不进入主线程而进入任务队列的任务。有时,什么任务应被定义为异步任务,这是由开发者决定的(比如你也可以把Ajax设为同步任务)。常见的异步任务主要有3类:

  • 网络请求(Ajax)
  • 事件触发(onclick | onchange etc.)
  • 定时函数(setTimeout | setInterval)

这些异步操作是由浏览器内核呈现引擎进行执行的。针对不同类型的异步任务,通常会开不同的线程执行(如事件触发线程、定时器触发线程(Timer)、异步http请求线程)。

 

三、微任务(microtask)与宏任务(macrotask)

处理异步任务的方法不同,JS中的任务还可分为:微任务和宏任务。微任务指的是在本轮事件循环中执行的异步任务,宏任务则指同步任务和下轮事件循环之后执行的异步任务。

微任务:Promise

宏任务:同步任务,定时任务(setTimeout | setInterval)

 

四、如何实现异步

我根据不同的异步场景,对相应的解决方案进行总结。

网络请求

在JS脚本中进行网络请求,即AJAX请求。

在浏览器呈现页面的过程中,当HTML解析器碰到<script>的时候,HTML文档的解析工作会暂停,先执行脚本。也可以将脚本标记为defer,在HTML文档解析完成后再执行。HTML5中增加了一个选项可标为异步,由其他线程解析和执行。(overview of the parsing model

解析到</script>时,会根据脚本中对DOM结构的操作调用树构造阶段,重新调整DOM树。因此<script>脚本通常放在HTML文档下方最后处理,避免反复修改或者产生我们不想要的效果。

1、XMLHttpRequest和AJAX

2、Promise和AJAX

Promise对象使得能够通过链式写法处理回调。它可以处理任何异步操作而不仅限于AJAX。

3、jQuery和AJAX

使用jQuery的相关对象处理AJAX不需要考虑浏览器问题,使得代码更简化。jQuery可以看做一个JavaScript更上一层的封装,AJAX的本质还是不变的。

jQuery在全局对象jQuery(即$)中绑定了ajax()函数来处理AJAX请求。jQuery中还存在jqXHR对象用链式写法处理回调。

4、Window.fetch

Fetch API 提供了请求资源的接口(包括网络资源),并返回一个Promise对象。

5、Ajxos等库

总结:Ajax本质不变,实现它的方式多种多样。

事件触发

定时任务

定时任务通常使用setTimeout()、setInterval() 两个方法实现。

(施工中)