JS事件循环(Event Loop)机制
前言
众所周知,为了与浏览器进行交互,Javascript是一门非阻塞单线程脚本语言。
为何单线程? 因为如果在DOM操作中,有两个线程一个添加节点,一个删除节点,浏览器并不知道以哪个为准,所以只能选择一个主线程来执行代码,以防止冲突。虽然如今添加了webworker等新技术,但其依然只是主线程的子线程,并不能执行诸如I/O类的操作。长期来看,JS将一直是单线程。
为何非阻塞?因为单线程意味着任务需要排队,任务按顺序执行,如果一个任务很耗时,下一个任务不得不等待。所以为了避免这种阻塞,我们需要一种非阻塞机制。这种非阻塞机制是一种异步机制,即需要等待的任务不会阻塞主执行栈中同步任务的执行。这种机制是如下运行的:
- 所有同步任务都在主线程上执行,形成一个
执行栈(execution context stack)
- 等待任务的回调结果进入一种
任务队列(task queue)
。 - 当主执行栈中的同步任务执行完毕后才会读取
任务队列
,任务队列中的异步任务(即之前等待任务的回调结果)会塞入主执行栈, - 异步任务执行完毕后会再次进入下一个循环。此即为今天文章的主角
事件循环(Event Loop)
用一张图展示这个过程:
Markdown- 所有同步任务都在主线程上执行,形成一个
正文
1.macro task与micro task
在实际情况中,上述的任务队列(task queue)
中的异步任务分为两种:微任务(micro task)
和宏任务(macro task)
。
- micro task事件:
Promises(浏览器实现的原生Promise)
、MutationObserver
、process.nextTick
<br /> - macro task事件:
setTimeout
、setInterval
、setImmediate
、I/O
、UI rendering
这里注意:script(整体代码)
即一开始在主执行栈中的同步代码本质上也属于macrotask,属于第一个执行的task
microtask和macotask执行规则:
- macrotask按顺序执行,浏览器的ui绘制会插在每个macrotask之间
- microtask按顺序执行,会在如下情况下执行:
- 每个callback之后,只要没有其他的JS在主执行栈中
- 每个macrotask结束时
下面来个简单例子:
- console.log(1);
- setTimeout(function() {
- console.log(2);
- }, 0);
- new Promise(function(resolve,reject){
- console.log(3)
- resolve()
- }).then(function() {
- console.log(4);
- }).then(function() {
- console.log(5);
- });
- console.log(6);
一步一步分析如下:
- 1.同步代码作为第一个macrotask,按顺序输出:1 3 6
- 2.microtask按顺序执行:4 5
- 3.microtask清空后执行下一个macrotask:2
再来一个复杂的例子:
- // 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);
假设我们创建一个有里外两部分的正方形盒子,里外都绑定了点击事件,此时点击内部,代码会如何执行?一步一步分析如下:
- 1.触发内部click事件,同步输出:click
- 2.将setTimeout回调结果放入macrotask队列
- 3.将promise回调结果放入microtask
- 4.将Mutation observers放入microtask队列,主执行栈中onclick事件结束,主执行栈清空
- 5.依序执行microtask队列中任务,输出:promise mutate
- 6.注意此时事件冒泡,外部元素再次触发onclick回调,所以按照前5步再次输出:click promise mutate(我们可以注意到事件冒泡甚至会在microtask中的任务执行之后,microtask优先级非常高)
- 7.macrotask中第一个任务执行完毕,依次执行macrotask中剩下的任务输出:timeout timeout
JS事件循环(Event Loop)机制的更多相关文章
- JavaScript事件循环(Event Loop)机制
JavaScript 是单线程单并发语言 什么是单线程 主程序只有一个线程,即同一时间片断内其只能执行单个任务. 为什么选择单线程? JavaScript的主要用途是与用户互动,以及操作DOM.这决定 ...
- 事件循环 event loop 究竟是什么
事件循环 event loop 究竟是什么 一些概念 浏览器运行时是多进程,从任务管理器或者活动监视器上可以验证. 打开新标签页和增加一个插件都会增加一个进程,如下图:  浏览器渲染进程是多线程,包 ...
- 事件循环Event loop到底是什么
摘要:本文通过结合官方文档MDN和其他博客深入解析浏览器的事件循环机制,而NodeJS有另一套事件循环机制,不在本文讨论范围中.process.nextTick和setImmediate是NodeJS ...
- 简单了解一下事件循环(Event Loop)
关于我 一个有思想的程序猿,终身学习实践者,目前在一个创业团队任team lead,技术栈涉及Android.Python.Java和Go,这个也是我们团队的主要技术栈. Github:https:/ ...
- 浏览器与Node的事件循环(Event Loop)有何区别?
前言 本文我们将会介绍 JS 实现异步的原理,并且了解了在浏览器和 Node 中 Event Loop 其实是不相同的. 一.线程与进程 1. 概念 我们经常说 JS 是单线程执行的,指的是一个进程里 ...
- JavaScript 事件循环 — event loop
引言 相信所有学过 JavaScript 都知道它是一门单线程的语言,这也就意味着 JS 无法进行多线程编程,但是 JS 当中却有着无处不在的异步概念 .在初期许多人会把异步理解成类似多线程的编程模式 ...
- JavaScipt 中的事件循环(event loop),以及微任务 和宏任务的概念
说事件循环(event loop)之前先要搞清楚几个问题. 1. js为什么是单线程的? 试想一下,如果js不是单线程的,同时有两个方法作用dom,一个删除,一个修改,那么这时候浏览器该听谁的? ...
- 一文梳理JavaScript 事件循环(Event Loop)
事件循环(Event Loop),是每个JS开发者都会接触到的概念,但是刚接触时可能会存在各种疑惑. 众所周知,JS是单线程的,即同一时间只能运行一个任务.一般情况下这不会引发问题,但是如果我们有一个 ...
- 事件循环Event Loop
在 事件循环 期间的某个时刻,运行时会从最先进入队列的消息开始处理队列中的消息.被处理的消息会被移出队列,并作为输入参数来调用与之关联的函数.正如前面所提到的,调用一个函数总是会为其创造一个新的栈帧. ...
随机推荐
- 115-基于TI TMS320DM6467T Camera Link 机器视觉 智能图像分析平台
基于TI TMS320DM6467无操作系统Camera Link智能图像分析平台 1.板卡概述 该板卡是我公司推出的一款具有超高可靠性.效率最大化.无操作系统的智能视频处理卡,是机器视觉开发上的首选 ...
- 第四章 走进jVM
4.1字节码 java文件编译成字节码后由默认解释执行,热点代码编译执行.方法调用到一定程度的时候,进行JIT编译成机器码执行,后面直接运行JIT编译结果(机器码). 4.2类加载过程 加载链接初始化 ...
- 【LeetCode】一种博弈思路 minimax(共5题)
[292] Nim Game (2019年3月12日,E) 有一堆石头,游戏规则是每次可以从里面拿1-3颗石头,拿到最后的石头的人赢.你和你的对手都 optimal 的玩这个游戏,问先手(也就是你)能 ...
- 输出匹配项:grep
命令格式: grep pattern [file...] When grep encounters a "pattern" in the file, it prints out t ...
- Linux用户登出之后保持后台进程(nohup)
使用&可以将进程置于后台,但是用户从Shell登出之后,进程会自动结束.想要在登出之后保持进程运行,就要结合nohup命令使用. 例如: nohup find -size +100k > ...
- Arthas阿里开源的 Java 诊断工具
当你遇到以下类似问题而束手无策时,Arthas可以帮助你解决: 1.这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception? 2.我改的代码为什么没有执行到?难道是我没 commi ...
- Halo(六)
Spring publish-event 机制 监听者模式包含了一个监听者 Listener 与之对应的事件 Event,还有一个事件发布者 EventPublish. 过程就是 EventPubli ...
- PHP 利用 curl 发送 post get del put patch 请求
因为需要在 php 开发中对接其它接口需要用 php curl 去对接其它接口 我把他们封装成函数 希望能对大家有所帮助. 这里面是封装好的会自动把 data 进行转成 json 格式,同时解码成 p ...
- powerdesigner 15.1 逆向工程 sqlserver2008 、sqlserver2005 带注释
第一种方法:在第一个网址里面的代码可以直接赋值到对应位置即可 http://wjqe.blog.163.com/blog/static/19938452011612536439/ 第二种方法:可塑性较 ...
- 重温HTML和CSS3
重温Web前端基础 本篇幅中着重文字,只是记录一些自己的见解,巩固下自身基础 网页结构是什么? 结构层 html 导航,列表,段文字,图片,链接,表示层 css 颜色,大小,位置,行为层 JavaSc ...