浅谈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 相关文章推荐
XENON基于JSON变种
Jul 27 Javascript
JQuery入门—JQuery程序的代码风格详细介绍
Jan 03 Javascript
jquery ajax提交整个表单元素的快捷办法
Mar 27 Javascript
GridView中获取被点击行中的DropDownList和TextBox中的值
Jul 18 Javascript
浅析jquery ajax异步调用方法中不能给全局变量赋值的原因及解决方法
Jan 10 Javascript
sogou地图API用法实例教程
Sep 11 Javascript
jQuery中each()、find()和filter()等节点操作方法详解(推荐)
May 25 Javascript
JavaScript性能优化之函数节流(throttle)与函数去抖(debounce)
Aug 11 Javascript
使用jQuery ajaxupload插件实现无刷新上传文件
Apr 23 jQuery
VUE2.0 ElementUI2.0表格el-table自适应高度的实现方法
Nov 28 Javascript
vue+axios实现post文件下载
Sep 25 Javascript
vue 解决兄弟组件、跨组件深层次的通信操作
Jul 27 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
php去除头尾空格的2种方法
2015/03/16 PHP
PHP数组相加操作及与array_merge的区别浅析
2016/11/26 PHP
escape、encodeURI 和 encodeURIComponent 的区别
2009/03/02 Javascript
js页面跳转的问题(跳转到父页面、最外层页面、本页面)
2013/08/14 Javascript
javascript里绝对用的上的字符分割函数总结
2014/07/31 Javascript
JavaScript通过select动态更换图片的方法
2015/03/23 Javascript
如何根据百度地图计算出两地之间的驾驶距离(两种语言js和C#)
2015/10/29 Javascript
获取jqGrid中选择的行的数据
2016/11/30 Javascript
Js实现中国公民身份证号码有效性验证实例代码
2017/05/03 Javascript
js es6系列教程 - 基于new.target属性与es5改造es6的类语法
2017/09/02 Javascript
基于vue.js快速搭建图书管理平台
2017/10/29 Javascript
ES7中利用Await减少回调嵌套的方法详解
2017/11/01 Javascript
详解Vue CLI3配置之filenameHashing使用和源码设计使用和源码设计
2018/08/31 Javascript
vue 刷新之后 嵌套路由不变 重新渲染页面的方法
2018/09/13 Javascript
webpack4 配置 ssr 环境遇到“document is not defined”
2019/10/24 Javascript
基于JavaScript伪随机正态分布代码实例
2019/11/07 Javascript
JS实现音量控制拖动
2020/01/15 Javascript
[36:09]Secret vs VG 2019国际邀请赛淘汰赛 败者组 BO3 第一场 8.24
2019/09/10 DOTA
Python简单生成随机姓名的方法示例
2017/12/27 Python
python高阶爬虫实战分析
2018/07/29 Python
解决pycharm的Python console不能调试当前程序的问题
2019/01/20 Python
python调用并链接MATLAB脚本详解
2019/07/05 Python
Python实现滑动平均(Moving Average)的例子
2019/08/24 Python
python进程间通信Queue工作过程详解
2019/11/01 Python
Python如何使用paramiko模块连接linux
2020/03/18 Python
Python 使用Opencv实现目标检测与识别的示例代码
2020/09/08 Python
Python 中 sorted 如何自定义比较逻辑
2021/02/02 Python
使用HTML5中的contentEditable来将多行文本自动增高
2016/03/01 HTML / CSS
大学四年规划书范文
2013/12/27 职场文书
团组织关系介绍信
2014/01/12 职场文书
大队委竞选演讲稿
2014/04/28 职场文书
2014年国庆晚会主持词
2014/09/19 职场文书
写给女朋友的检讨书
2015/05/06 职场文书
MySQL数据库压缩版本安装与配置详细教程
2021/05/21 MySQL
美国运营商 T-Mobile 以 117.83Mb/s 的速度排第一位
2022/04/21 数码科技
python中Pyqt5使用Qlabel标签播放视频
2022/04/22 Python