- 已编辑
最开始通过看ES5教程了解JS异步操作时,理解了JS的单线程模型和事件循环机制,教程中也介绍了实现JS异步操作的方法。但是我还是一头雾水,为什么需要异步操作?怎么划分异步操作和同步操作?应该在哪里进行异步操作?我脑中都是模糊的概念。后来我发现我就是少根筋,我只是需要了解一下异步操作的使用场景和通常的异步任务。
注意:JS层面的异步和操作系统层面的异步(涉及进程线程并发)是有所区别的,建议分开看待,不易混淆。
一、JS的单线程模型和事件循环机制
当我们谈论JS层面的异步时,不得不谈JS单线程模型和事件循环机制。这是JS异步概念的来源。
JS的单线程模型意味着,在执行JS时只有一个主线程,每个任务必须顺序执行。如果当前任务执行时间过长,会导致接下来的所有任务都处于阻塞状态,进而导致浏览器卡死等我们不希望看到的状况。为了解决这一问题,事件循环机制(Event Loop)被发明出来。
事件循环机制中,负责执行JS脚本的单线程我们称为主线程,在内存中表现为一个执行栈,JS只通过主线程执行任务。异步任务被挂起,存储在堆中,当异步任务准备就绪,它对应的事件便进入任务队列。主线程首先执行同步任务,然后查看任务队列是否有就绪的异步任务(或者时间到了的异步任务),调用相应的回调函数执行,直到任务队列为空。至此即完成一个事件循环。如下图所示。
二、异步任务
异步任务指的是被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
利用XMLHttpRequest对象实现AJAX
2、Promise和AJAX
Promise对象使得能够通过链式写法处理回调。它可以处理任何异步操作而不仅限于AJAX。
利用Promise来处理AJAX
3、jQuery和AJAX
使用jQuery的相关对象处理AJAX不需要考虑浏览器问题,使得代码更简化。jQuery可以看做一个JavaScript更上一层的封装,AJAX的本质还是不变的。
jQuery在全局对象jQuery(即$)中绑定了ajax()函数来处理AJAX请求。jQuery中还存在jqXHR对象用链式写法处理回调。
利用jQuery中的ajax()来处理AJAX
利用jQuery中的jqXHR对象来处理AJAX
4、Window.fetch
Fetch API 提供了请求资源的接口(包括网络资源),并返回一个Promise对象。
5、Ajxos等库
版权声明:本文由[ po4kee]发表于 https://blog.csdn.net/po4kee/article/details/88385494