JS前端宏任务微任务及Event Loop使用详解


Posted in Javascript onJuly 23, 2022

前言

首先我们要了解javascript是一个单线程的脚本语言,也就是说我们在执行代码的过程中不会出现同时进行两个进程(执行两段代码)。

Javascript语言将任务的执行模式分成两种:同步(Synchronous)和异步(Asynchronous)。

同步:一个进程在执行某个请求的时候,若该请求需要一段时间才能返回信息,那么这个进程将会一直等待下去,直到收到返回信息才继续执行下去。

异步:进程不需要一直等下去,而是继续执行下面的操作,不管其他进程的状态。当有消息返回时系统会通知进程进行处理,这样可以提高执行的效率。

进程:狭义上,就是正在运行的程序的实例。广义上,进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。描述的是CPU在运行指令及加载和保存上下文所需要的时间。

线程:是程序中一个单一的顺序控制流程。进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位。指运行中的程序的调度单位。

执行栈:V8(谷歌浏览器引擎)内部维护出来的一个用来存放函数的执行上下文环境的一个栈结构。

相信有不少人和我有着一样的疑惑,既然javascript是单线程的脚本语言,那么他有什么优势呢,为什么不写成多进程的呢?

  • 单线程不仅可以节省内存同时也可以节省上下文切换时间;
  • 不会和渲染线程冲突(如果JS是双线程的,当页面渲染线程还在执行时,JS已经将渲染页面的参数修改,就会导致页面渲染出现问题)

宏任务

(macro)task,可以理解是每次执行栈执行的代码就是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行)。

宏任务队列

  • I/O
  • UI-rendering (页面渲染)
  • script
  • setTimeout
  • setInterval
  • setImmediate (node环境下是,而浏览器环境下不是)
  • requestAnimationFrame (在浏览器环境是,而node环境不是)

requestAnimationFrame在MDN的定义为,下次页面重绘前所执行的操作,而重绘也是作为宏任务的一个步骤来存在的,且该步骤晚于微任务的执行。

微任务

microtask,可以理解是在当前 task 执行结束后立即执行的任务。也就是说,在当前task任务后,下一个task之前,在渲染之前。

所以它的响应速度相比setTimeout(setTimeout是task)会更快,因为无需等渲染。也就是说,在某一个macrotask执行完后,就会将在它执行期间产生的所有microtask都执行完毕(在渲染前)。

微任务队列

  • process.nextTick (node环境下是,而浏览器环境下不是)
  • promise.then
  • MutationObserver (在浏览器环境是,而node环境不是)

Event-Loop

上面我们讲了半天宏任务、微任务等各种任务的执行那么vent-Loop到底是个啥?

javascript是一个单进程的语言,同一时间不能处理多个任务,所以什么时候执行宏任务什么时候执行微任务呢?于是乎我们需要Event Loop-事件循环机制(计算机系统的一种运作机制)这样一个判断逻辑存在。

同步代码: js为脚本语言,对于同步代码来说,自上而下进行解释执行。

异步代码: 对于一个任务,分为多个片段来进行执行, 先执行一段,如果碰到比较耗时间的操作,比如本地或者网络io请求。 第一段开始进行io之后,把执行权交由其他任务,当io完成后再来执行后半段的任务(io操作比较耗时,在系统进行io时,主线程是空闲的)

执行顺序

1. 首先执行同步代码,这属于宏任务;

2. 当执行完所有的同步代码后,执行栈为空,检查是否有异步代码要执行;

3. 执行微任务;

4. 执行完微任务后,有必要的情况下会渲染页面;

5. 开启下一轮 Event Loop,执行宏任务中的代码;

代码在执行过程中,遇到异步代码,会将异步代码用队列装起来(挂起)

实战出真理,我们用一个?感受一下
console.log('start');          // 1
function foo(){
   console.log('foo');           
}
foo()                          // 2
setTimeout(function() {        //异步代码中的宏任务,先挂起
   console.log('setTimeout'); // 7
},1000)
new Promise(resolve =>{
   console.log('promise');    // 3
   resolve()
})
   .then(function() {        //异步代码中的微任务,先挂起
       console.log('promise1');// 5
   })
   .then(function() {        //异步代码中的微任务,先挂起
       console.log('promise2');// 6
   })
console.log('end');            // 4

我们跟着实行顺序来分析,第一步首先执行同步代码,所以首先打印出来‘start’,调用函数foo打印出来‘foo’,执行Promise函数打印出来‘promise’,最后打印出来‘end’同步代码就执行完毕,再检查是否有异步代码要执行,第三步执行微任务,所以先打印出第一微任务列表中的‘promise1’,紧接着打印第二微任务列表中的‘promise2’纯js不用渲染页面,最后开启下一轮的Event-Loop,执行宏任务中的代码,而setTimeout就是异步代码中的宏任务所以最终打印出来‘setTimeout’,最后我们来看看在谷歌浏览器中的打印效果。

JS前端宏任务微任务及Event Loop使用详解

这里有个小细节,如果将定时器setTimeout的时间设置为0呢?结果其实还是一样的,setTimeout不会因为时间而改变执行顺序,因为它仍然是异步代码中的宏任务,不会因为延迟执行的时间而改变。

结语

以上就是我对于宏任务、微任务以及事件循环机制(Event Loop)的一些浅显的认识与理解,更多关于JS宏任务微任务Event Loop的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
点击隐藏页面左栏或右栏实现js代码
Apr 01 Javascript
JS getAttribute和setAttribute(取得和设置属性)的使用介绍
Jul 10 Javascript
AngularJS基础 ng-dblclick 指令用法
Aug 01 Javascript
bootstrapValidator bootstrap-select验证不可用的解决办法
Jan 11 Javascript
js for循环倒序输出数组元素的实例
Mar 01 Javascript
JavaScript数据类型的存储方法详解
Aug 25 Javascript
node.js学习之事件模块Events的使用示例
Sep 28 Javascript
利用jqgrid实现上移下移单元格功能
Nov 07 Javascript
微信小程序如何实现全局重新加载
Jun 05 Javascript
解决js中的setInterval清空定时器不管用问题
Nov 17 Javascript
Vant+postcss-pxtorem 实现浏览器适配功能
Feb 05 Javascript
如何用Node.js编写内存效率高的应用程序
Apr 30 Javascript
关于对TypeScript泛型参数的默认值理解
Jul 15 #Javascript
vue递归实现树形组件
Jul 15 #Vue.js
VUE递归树形实现多级列表
Jul 15 #Vue.js
javascript进阶篇深拷贝实现的四种方式
Jul 07 #Javascript
js面向对象编程OOP及函数式编程FP区别
Jul 07 #Javascript
类和原型的设计模式之复制与委托差异
JS高级程序设计之class继承重点详解
Jul 07 #Javascript
You might like
全国FM电台频率大全 - 16 河南省
2020/03/11 无线电
php模拟socket一次连接,多次发送数据的实现代码
2011/07/26 PHP
19个超实用的PHP代码片段
2014/03/14 PHP
PHP中使用hidef扩展代替define提高性能
2015/04/09 PHP
thinkPHP框架通过Redis实现增删改查操作的方法详解
2019/05/13 PHP
各种效果的jquery ui(接口)介绍
2008/09/17 Javascript
jquery.artwl.thickbox.js  一个非常简单好用的jQuery弹出层插件
2012/03/01 Javascript
JS编程小常识很有用
2012/11/26 Javascript
jquery 事件冒泡的介绍以及如何阻止事件冒泡
2012/12/25 Javascript
Javascript算符的优先级介绍
2013/03/20 Javascript
jquery的父子兄弟节点查找示例代码
2014/03/03 Javascript
Javascript的setTimeout()使用闭包特性时需要注意的问题
2014/09/23 Javascript
jquery动态分页效果堪比时光网
2014/09/25 Javascript
JavaScript判断前缀、后缀是否是空格的方法
2015/04/15 Javascript
jquery制作图片时钟特效
2020/03/30 Javascript
基于jquery实现智能提示控件intellSeach.js
2016/03/17 Javascript
Jquery on方法绑定事件后执行多次的解决方法
2016/06/02 Javascript
JS实现的tab切换选项卡效果示例
2017/02/28 Javascript
微信小程序本地缓存数据增删改查实例详解
2017/05/24 Javascript
原生JavaScrpit中异步请求Ajax实现方法
2017/11/03 Javascript
细说webpack源码之compile流程-rules参数处理技巧(2)
2017/12/26 Javascript
[54:26]完美世界DOTA2联赛PWL S3 Forest vs Rebirth 第一场 12.10
2020/12/12 DOTA
python调用java的Webservice示例
2014/03/10 Python
Python实现mysql数据库更新表数据接口的功能
2017/11/19 Python
Python常用库Numpy进行矩阵运算详解
2020/07/21 Python
职高毕业生自我鉴定
2013/10/21 职场文书
机械设计专业应届生求职信
2013/11/21 职场文书
邮政员工辞职信
2014/01/16 职场文书
辞职信模板(中英文版)
2015/02/27 职场文书
农村环境卫生倡议书
2015/04/29 职场文书
Python数据可视化之绘制柱状图和条形图
2021/05/25 Python
只需要100行Python代码就可以实现的贪吃蛇小游戏
2021/05/27 Python
Android自定义ScrollView实现阻尼回弹
2022/04/01 Java/Android
未发现nvidia显卡怎么办?Win11系统中未检测到nvidia显卡解决教程
2022/04/08 数码科技
MySQL的存储过程和相关函数
2022/04/26 MySQL
Nginx报错104:Connection reset by peer问题的解决及分析
2022/07/23 Servers