JS事件循环,MACRO TASK,MICRO TASK
事件循环的基本概念
- JS执行的过程中,由JS引擎控制的函数调用栈来控制时间循环
- 定时器线程,事件触发线程,异步http请求线程控制异步的任务队列
- 任务分为macro task,micro task 对应都有不同的任务队列
- macro task:script正常代码,setTimeout,setInterval,I/O,UI rendering
- 由事件触发线程维护
- micro task:process.nextTick,promise,mutationObserve
- 由JS引擎线程维护
- 最终在函数调用栈中完成
- macro task:script正常代码,setTimeout,setInterval,I/O,UI rendering
事件循环执行的顺序
- 执行函数调用栈中的macro task,直到调用栈清空(剩下全局)
- 执行job queues中所有可执行的micro tasks
- 执行UI render
- 从事件队列中获取macro task,开始新的事件循环
例子
<div class="outer" style="width:200px;height:200px;background-color: #ccc">
1
<div class="inner" style="width:100px;height:100px;background-color: #ddd">begin</div>
</div>
// Let's get hold of those elements
var outer = document.querySelector('.outer');
var inner = document.querySelector('.inner'); var i = 0; // 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() {
i++; if(i === 1) {
inner.innerHTML = 'end';
} console.log('click'); setTimeout(function() {
alert('锚点');
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 div 时程序依次的执行顺序是:
- onclick 入 JS stack
- 打印出 click
- 将 timeout 压入到 macrotask
- 将 promise 压入到 microtask
- 修改 outer 属性 data-random
- 将 mutate 压入到 microtask,
- onclick 出 JS stack
此时,由于用户点击事件onclick产生的macrotask执行完毕,JS stack 清空,开始执行microtask.
- promise 入 JS stack
- 打印出 promise
- promise 出 JS stack
- mutate 入 JS stack
- 打印出 mutate
- mutate 出 JS stack
此时,microtask 执行完毕,JS stack 清空,但是由于事件冒泡,接着执行outer上的onclick事件.
- onclick 入 JS stack
- 打印出 click
- 将 timeout 压入到 macrotask
- 将 promise 压入到 microtask
- 修改 outer 属性 data-random
- 将 mutate 压入到 microtask,
- onclick 出 JS stack
此时,由于outer上的onclick事件产生的macrotask执行完毕,JS stack 清空,开始执行microtask.
- promise 入 JS stack
- 打印出 promise
- promise 出 JS stack
- mutate 入 JS stack
- 打印出 mutate
- mutate 出 JS stack
此时,本轮事件循环结束,UI 开始 render.
- 页面中inner的innerHTML变为end
此时,UI render 完毕,开始下一轮事件循环.
- timeout 入 JS stack
- 弹出警告 锚点.
- 打印出 timeout
- timeout 出 JS stack
- timeout 入 JS stack
- 弹出警告 锚点.
- 打印出 timeout
- timeout 出 JS stack
到此为止,整个事件执行完毕,我们可以看到在弹出警告框之前inner的内容已经改变。
那如果不是用户点击事件触发onclick,而是js触发呢?
inner.addEventListener('click', onClick);
outer.addEventListener('click', onClick);
inner.click();
此时的执行顺序是:
- 首先是script(整体代码)入 JS stack
- onclick 入 JS stack
- 打印出 click
- 将 timeout 压入到 macrotask
- 将 promise 压入到 microtask
- 修改 outer 属性 data-random
- 将 mutate 压入到 microtask,
- onclick 出 JS stack
此时,inner 的 onclick 已经出 JS stack,但是script(整体代码)还没有出 JS stack,还不能执行microtask,由于冒泡,接着执行 outer 的 onclick.
- onclick 入 JS stack
- 打印出 click
- 将 timeout 压入到 macrotask
- 将 promise 压入到 microtask
- 修改 outer 属性 data-random
接着执行的outer.setAttribute('data-random', Math.random());,但是由于上一个mutation microtask还处于等待状态,不能再添加mutation microtask,所以这里不会将 mutate 压入到 microtask。接着执行:
- onclick 出 JS stack
- script(整体代码)出 JS stack
此时,inner.click()执行完毕,script(整体代码)已出 JS stack,JS stack 清空,开始执行mircotask.
- promise 入 JS stack
- 打印出 promise
- promise 出 JS stack
- mutate 入 JS stack
- 打印出 mutate
- mutate 出 JS stack
- promise 入 JS stack
- 打印出 promise
- promise 出 JS stack
此时,所有的mircotask执行完毕,本轮事件循环结束,UI 开始 render.
- 页面中inner的innerHTML变为end
此时,UI render 完毕,开始下一轮事件循环.
- timeout 入 JS stack
- 弹出警告 锚点.
- 打印出 timeout
- timeout 出 JS stack
- timeout 入 JS stack
- 弹出警告 锚点.
- 打印出 timeout
- timeout 出 JS stack
到此为止,整个事件执行完毕,我们可以看到在弹出警告框之前inner的内容已经改变。
参考文献:
https://segmentfault.com/a/1190000013212944
http://zhangxiang958.github.io/2018/02/03/Event%20Loop%20中的%20microtask%20与%20macrotask/
JS事件循环,MACRO TASK,MICRO TASK的更多相关文章
- Node.js 事件循环(Event Loop)介绍
Node.js 事件循环(Event Loop)介绍 JavaScript是一种单线程运行但又绝不会阻塞的语言,其实现非阻塞的关键是“事件循环”和“回调机制”.Node.js在JavaScript的基 ...
- Node.js事件循环
Node JS是单线程应用程序,但它通过事件和回调概念,支持并发. 由于Node JS每一个API是异步的,作为一个单独的线程,它使用异步函数调用,以保持并发性.Node JS使用观察者模式.Node ...
- js事件循环机制辨析
对于新接触js语言的人来说,最令人困惑的大概就是事件循环机制了.最开始这也困惑了我好久,花了我几个月时间通过书本,打代码,查阅资料不停地渐进地理解他.接下来我想要和大家分享一下,虽然可能有些许错误的 ...
- 6、Node.js 事件循环
#########################################################################################Node.js 事件循 ...
- js——事件循环
JS-事件循环 js运行的环境称之为宿主环境. 执行栈 :call stack ,一个数据结构,用于存放各种函数的执行环境,每一个函数执行之前他的相关信息会加入到执行栈中,函数调用之前,创建执行环境, ...
- 深入理解 JavaScript 事件循环(二)— task and microtask
引言 microtask 这一名词是 JS 中比较新的概念,几乎所有人都是在学习 ES6 的 Promise 时才接触这一新概念,我也不例外.当我刚开始学习 Promise 的时候,对其中回调函数的执 ...
- [译] 深入理解 JavaScript 事件循环(二)— task and microtask
引言 microtask 这一名词是 JS 中比较新的概念,几乎所有人都是在学习 ES6 的 Promise 时才接触这一新概念,我也不例外.当我刚开始学习 Promise 的时候,对其中回调函数的执 ...
- JS事件循环(Event Loop)机制
前言 众所周知,为了与浏览器进行交互,Javascript是一门非阻塞单线程脚本语言. 为何单线程? 因为如果在DOM操作中,有两个线程一个添加节点,一个删除节点,浏览器并不知道以哪个为准,所以只能选 ...
- js事件循环
之前有看过一些事件循环的博客,不过一阵子没看就发现自己忘光了,所以决定来自己写一个博客总结下! 首先,我们来解释下事件循环是个什么东西: 就我们所知,浏览器的js是单线程的,也就是说,在同一时刻,最多 ...
随机推荐
- VS #include 【bits/bstdc++.h】出错
目录 1. 本文地址 2. 按 3. 操作步骤 1. 本文地址 博客园:https://www.cnblogs.com/coco56/p/11163142.html 简书:https://www.ji ...
- 基于Xilinx Kintex-7 XC7K325T 的FMC USB3.0 SATA 四路光纤数据转发卡
基于Xilinx Kintex-7 XC7K325T 的FMC USB3.0 SATA 四路光纤数据转发卡 1. 板卡概述 本板卡基于Xilinx公司的FPGAXC7K325T-2FFG900 芯片, ...
- mysql查询每个部门/班级前几名
Employee 表包含所有员工信息,每个员工有其对应的 Id, salary 和 department Id . +----+-------+--------+--------------+ | I ...
- Redis复制实现原理
摘要 我的前一篇文章<Redis 复制原理及特性>已经介绍了Redis复制相关特性,这篇文章主要在理解Redis复制相关源码的基础之上介绍Redis复制的实现原理. Redis复制实现原理 ...
- JAVA泛型通配符T,E,K,V区别,T以及Class<T>,Class<?>的区别
1. 先解释下泛型概念 泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数.这种参数类型可以用在类.接口和方法的创建中,分别称为泛型类.泛型接口.泛 ...
- MySQL数据库5事务、视图、触发器、函数、数据库的备份
目录 一.事务(important) 1.1什么是事务? 1.2解决办法 1.2.1事务的语法 1.2.2使用事务解决转账问题代码演示 1.2.3rollback 1.3事务的特性(important ...
- 【leetcode】1028. Recover a Tree From Preorder Traversal
题目如下: We run a preorder depth first search on the root of a binary tree. At each node in this traver ...
- pypi 清华镜像使用帮助
清华镜像 地址 https://mirrors.tuna.tsinghua.edu.cn/help/pypi/ 临时使用 pip install -i https://pypi.tuna.tsingh ...
- shell学习记录----初识sed和gawk
Linux命令行与shell脚本编程大全中关于sed和gawk的介绍合在一起,而且结构有点乱. 不像之前的命令写的很清楚.所以这次我需要写下来整理一下. 一.sed部分 1.1 sed命令格式如下: ...
- PHP Timer 页面运行时间监测类
转至:http://blog.csdn.net/fdipzone/article/details/20160567 php Timer 页面运行时间监测类,可按不同key监测不同的运行时间 Timer ...