浅谈javascript事件环微任务和宏任务队列原理


Posted in Javascript onSeptember 12, 2020

JS 事件环

JS 程序的运行是离不开事件环机制的,这个机制保证在发生某些事情的时候我们有机会执行一个我们事先预定好的函数,事情发生的时候 JS 会将相应的函数入栈执行然后出栈,但是关于事件环我们还有一些未知的东西,例如,setTimeout 我们习惯称他为定时器,但是可能很多人没有意识到,这个东西和我们常用的一些事件没什么不同,只不过我们通常所说的事件大多需要用户触发,而 setTimeout 不用用户自己触发,而是指定时间之后触发;那么问题来了,如果我们将时间设置为 0 会发生什么?会立即执行么?

setTimeout、DOM或者 HTTP请求这部分其实并不在 v8 引擎中,这些属于 web API,javascript 是一个单线程的语言,也就意味着一次只能做一件事情,这个事实从未改变

执行原理

JS 中所有的方法都会被推入栈中执行,执行完成被弹出,在遇到异步代码的时候,例如 setTimeout MutationObserver Promise 异步的部分会由其他掌管 webAPI 的地方执行,等异步有结果之后,回调函数会进入相应的队列,Promise MutationObserver 回调进入微任务队列,setTimeout setInterval requestAnimationFrame 进入宏任务队列。等待主线程的执行栈空了,微任务队列立刻被推入栈中执行,执行完毕开始执行宏任务队列

浅谈javascript事件环微任务和宏任务队列原理

一个经典的例子

html

<div class="outer">
 <div class="inner"></div>
</div>

js

// Let's get hold of those elements
var outer = document.querySelector('.outer');
var inner = document.querySelector('.inner');

// Let's listen for attribute changes on the
// outer element
new MutationObserver(function () {
 console.log('mutate');
}).observe(outer, {
 attributes: true,
});

// Here's a click listener…
function onClick() {
 console.log('click');

 setTimeout(function () {
  console.log('timeout');
 }, 0);

 Promise.resolve().then(function () {
  console.log('promise');
 });

 outer.setAttribute('data-random', Math.random());
}

// …which we'll attach to both elements
inner.addEventListener('click', onClick);
outer.addEventListener('click', onClick);

以上代码在,手动点击 inner 元素的时候会有如下输出

click
promise
mutate
click
promise
mutate
timeout
timeout

截止 2020年8月份 chrome edge opera firefox 的结果是统一的,但是在此之前的版本可能会有不同的输出。

一个奇怪的现象

上述代码我们不使用手动触发点击,而是使用 inner.click() 触发点击,其结果会有很大的不同

click
click
promise
mutate
promise
timeout
timeout

造成以上巨大差异的原因是,手动点击,不是通过函数进入执行栈的方式触发点击事件的回调,所以inner 的回调执行完了主线程中的执行栈就是空的可以直接执行队列中任务,然后事件冒泡导致的回调函数才被推入栈运行;而 click 方法的点击则是通过将 click 推入栈中执行来达到的,inner 的点击回调执行完了之后 click 方法并没有被弹出栈,而是直接执行冒泡的下一个回调,由于下一个回调有一个重复的 属性设置 这是不会重复触发 MutationObserver的所以 mutate 的输出只会有一个。等所有的冒泡回调被执行完毕 click 函数才会被弹出栈。

最后注意,浏览器会尽量预先执行较为敏感的操作。

以上就是浅谈javascript事件环微任务和宏任务队列原理的详细内容,更多关于JavaScript 事件环的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
JavaScript 入门·JavaScript 具有全范围的运算符
Oct 01 Javascript
热点新闻滚动特效的js代码
Aug 17 Javascript
js控制iframe的高度/宽度让其自适应内容
Apr 09 Javascript
JavaScript面向对象程序设计教程
Mar 29 Javascript
基于Node.js的WebSocket通信实现
Mar 11 Javascript
详解vue-resource promise兼容性问题
Jun 20 Javascript
JavaScript基本语法_动力节点Java学院整理
Jun 26 Javascript
bootstrap时间插件daterangepicker使用详解
Oct 19 Javascript
jQuery访问json文件中数据的方法示例
Jan 28 jQuery
微信小程序云开发之使用云数据库
May 17 Javascript
解决layui的table插件无法多层级获取json数据的问题
Sep 19 Javascript
js实现贪吃蛇小游戏(加墙)
Jul 31 Javascript
返回上一个url并刷新界面的js代码
Sep 12 #Javascript
Vue和React有哪些区别
Sep 12 #Javascript
浅谈vue项目利用Hbuilder打包成APP流程,以及遇到的坑
Sep 12 #Javascript
解决vue项目 build之后资源文件找不到的问题
Sep 12 #Javascript
vue项目打包为APP,静态资源正常显示,但API请求不到数据的操作
Sep 12 #Javascript
vue v-on:click传递动态参数的步骤
Sep 11 #Javascript
vue Cli 环境删除与重装教程 - 版本文档
Sep 11 #Javascript
You might like
星际初学者游戏中永远要做的事
2020/03/04 星际争霸
PHP+DBM的同学录程序(5)
2006/10/09 PHP
判断是否为指定长度内字符串的php函数
2010/02/16 PHP
windows中为php安装mongodb与memcache
2015/01/06 PHP
PHP利用超级全局变量$_GET来接收表单数据的实例
2016/11/05 PHP
利用php-cli和任务计划实现刷新token功能的方法
2017/05/03 PHP
PHP实现的文件上传类与用法详解
2017/07/05 PHP
关于Aptana Studio生成自动备份文件的解决办法
2009/12/23 Javascript
JS面向对象编程之对象使用分析
2010/08/19 Javascript
js获取元素到文档区域document的(横向、纵向)坐标的两种方法
2013/05/17 Javascript
快速解决jquery之get缓存问题的最简单方法介绍
2013/12/19 Javascript
jQuery中ajax的load()方法用法实例
2014/12/26 Javascript
jquery带下拉菜单和焦点图代码分享
2015/08/24 Javascript
模仿password输入框的实现代码
2016/06/07 Javascript
js中常用的Math方法总结
2017/01/12 Javascript
bootstrap fileinput组件整合Springmvc上传图片到本地磁盘
2017/05/11 Javascript
BootStrap Select清除选中的状态恢复默认状态
2017/06/20 Javascript
浅析vue中的MVVM实现原理
2019/03/04 Javascript
python将字典内容存入mysql实例代码
2018/01/18 Python
python list元素为tuple时的排序方法
2018/04/18 Python
Python RabbitMQ消息队列实现rpc
2018/05/30 Python
pyqt5 tablewidget 利用线程动态刷新数据的方法
2019/06/17 Python
python多线程同步之文件读写控制
2021/02/25 Python
python 实现按对象传值
2019/12/26 Python
python 实现压缩和解压缩的示例
2020/09/22 Python
HTML5 UTF-8 中文乱码的解决方法
2013/11/18 HTML / CSS
Europcar葡萄牙:葡萄牙汽车和货车租赁
2017/10/13 全球购物
怎样声明接口
2014/09/19 面试题
应届生污水处理求职信
2013/11/06 职场文书
商务英语应届生自我鉴定
2013/12/08 职场文书
高级编程求职信模板
2014/02/16 职场文书
《中国梦我的梦》中学生演讲稿
2014/08/20 职场文书
小学生清明节演讲稿
2014/09/05 职场文书
python3 sqlite3限制条件查询的操作
2021/04/07 Python
Springboot如何同时装配两个相同类型数据库
2021/11/17 Java/Android
MySQL数据库完全卸载的方法
2022/03/03 MySQL