JavaScript事件循环(Event Loop)机制
JavaScript 是单线程单并发语言
什么是单线程
主程序只有一个线程,即同一时间片断内其只能执行单个任务。
为什么选择单线程?
JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。
单线程意味着什么?
单线程就意味着,所有任务都需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就需要一直等着。这就会导致
IO操作(耗时但cpu闲置)时造成性能浪费的问题。如何解决单线程带来的性能问题?
答案是异步!主线程完全可以不管IO操作,暂时挂起处于等待中的任务,先运行排在后面的任务。等到IO操作返回了结果,再回过头,把挂起的任务继续执行下去。于是,所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)
注: 当主线程阻塞时,任务队列仍然是能够被推入任务的
事件循环(Event Loop)
JavaScript 内存模型
讲事件循环之前,先看一张下网上看到的 JavaScript 内存模型,相信看完这个会对事件循环机制有一种豁然开朗的感觉。

- 调用栈(Call Stack):用于主线程任务的执行
- 堆(Heap): 用于存放非结构化数据,譬如程序分配的变量与对象
- 任务队列(Queue): 用于存放异步任务与定时任务。
JavaScript 代码执行机制:
- 所有同步任务都在主线程上的栈中执行。
- 主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
- 一旦"栈"中的所有同步任务执行完毕,系统就会读取"任务队列",选择出需要首先执行的任务(由浏览器决定,并不按序)。
Event Loop
现在我们来聊事件循环。事件循环顾名思义它就是一个循环,主线程会不断循环执行上面的第三步,其基本的代码逻辑如下所示:
while (queue.waitForMessage()) {
queue.processNextMessage();
}
常见异步任务进入任务队列时机
行为 时机 DOM操作 在用户点击等操作事件完成后 网络操作(Ajax等) 在网络操作响应后 定时器 在规定时间到达后 事件循环机制图解:

任务
MacroTask(Task)
setTimeout, setInterval, setImmediate, requestAnimationFrame, I/O, UI renderingMicroTask(在ES2015规范中称为Job)
process.nextTick, Promise, Object.observe, MutationObserver
规范:
- 每个浏览器环境,至多有一个event loop。
- 一个event loop可以有1个或多个task queue,而仅有一个 MicroTask Queue。
- 一个task queue是一列有序的task, 每个task定义时都有一个task source,从同一个task source来的task必须放到同一个task queue,从不同源来的则被添加到不同队列。
- tasks are scheduled,所以浏览器可以从内部到JS/DOM,保证动作按序发生。
- Microtasks are scheduled,Microtask queue 在当前 task queue 的结尾执行。microtask中添加的microtask也被添加到Microtask queue的末尾并处理。
注: event loop的每个turn,是由浏览器决定先执行哪个task queue。这允许浏览器为不同的task source设置不同的优先级,比如为用户交互设置更高优先级来使用户感觉流畅。
示例
function ELoop() {
// 当前任务
let p = new Promise((resolve, reject)=>{
console.log("current Task")
resolve();
});
let nextP;
setTimeout(()=>{
console.log("MacroTask_1");
nextP.then(()=>{
// 第一次执行时,这段代码并没有执行到。
console.log("MicroTask_promise_1"); //第一个MicroTask
})
console.log("MacroTask_1 end")
}, 0) // 第一个 MacroTask
setTimeout(()=>{
console.log("MacroTask_2");
console.log("MacroTask_2 end")
}, 0)// 第二个MacroTask
nextP = p.then(()=>{
console.log("MicroTask_promise_2"); //第一个MicroTask
console.log(1)
}).then(()=>{
console.log("MicroTask_promise_3"); // 第二个MicroTask
console.log(1)
})
console.log("current Task end")
}
ELoop();
/**输出结果:
current Task
MicroTask_promise_2
MicroTask_promise_3
MacroTask_1
MicroTask_promise_1
MacroTask_2
**/
参考文献:
从Promise来看JavaScript中的Event Loop、Tasks和Microtasks
JavaScript Event Loop 机制详解与 Vue.js 中实践应用
JavaScript 运行机制详解:再谈Event Loop
JavaScript事件循环(Event Loop)机制的更多相关文章
- JS事件循环(Event Loop)机制
前言 众所周知,为了与浏览器进行交互,Javascript是一门非阻塞单线程脚本语言. 为何单线程? 因为如果在DOM操作中,有两个线程一个添加节点,一个删除节点,浏览器并不知道以哪个为准,所以只能选 ...
- JavaScript 事件循环 — event loop
引言 相信所有学过 JavaScript 都知道它是一门单线程的语言,这也就意味着 JS 无法进行多线程编程,但是 JS 当中却有着无处不在的异步概念 .在初期许多人会把异步理解成类似多线程的编程模式 ...
- 一文梳理JavaScript 事件循环(Event Loop)
事件循环(Event Loop),是每个JS开发者都会接触到的概念,但是刚接触时可能会存在各种疑惑. 众所周知,JS是单线程的,即同一时间只能运行一个任务.一般情况下这不会引发问题,但是如果我们有一个 ...
- 事件循环Event loop到底是什么
摘要:本文通过结合官方文档MDN和其他博客深入解析浏览器的事件循环机制,而NodeJS有另一套事件循环机制,不在本文讨论范围中.process.nextTick和setImmediate是NodeJS ...
- 事件循环 event loop 究竟是什么
事件循环 event loop 究竟是什么 一些概念 浏览器运行时是多进程,从任务管理器或者活动监视器上可以验证. 打开新标签页和增加一个插件都会增加一个进程,如下图:  浏览器渲染进程是多线程,包 ...
- 简单了解一下事件循环(Event Loop)
关于我 一个有思想的程序猿,终身学习实践者,目前在一个创业团队任team lead,技术栈涉及Android.Python.Java和Go,这个也是我们团队的主要技术栈. Github:https:/ ...
- 浏览器与Node的事件循环(Event Loop)有何区别?
前言 本文我们将会介绍 JS 实现异步的原理,并且了解了在浏览器和 Node 中 Event Loop 其实是不相同的. 一.线程与进程 1. 概念 我们经常说 JS 是单线程执行的,指的是一个进程里 ...
- JavaScript:彻底理解同步、异步和事件循环(Event Loop) (转)
原文出处:https://segmentfault.com/a/1190000004322358 一. 单线程 我们常说"JavaScript是单线程的". 所谓单线程,是指在JS ...
- JavaScript:彻底理解同步、异步和事件循环(Event Loop)
一. 单线程 我们常说"JavaScript是单线程的". 所谓单线程,是指在JS引擎中负责解释和执行JavaScript代码的线程只有一个.不妨叫它主线程. 但是实际上还存在其他 ...
随机推荐
- HDU--1358--KMP算法失配函数getfail()的理解--Period
/* Name: hdu--1358--Period Author: 日天大帝 Date: 20/04/17 10:24 Description: 长度/向后移动的位数 = 出现的次数 kmp其实匹配 ...
- 安徽省2016“京胜杯”程序设计大赛_K_纸上谈兵
纸上谈兵 Time Limit: 1000 MS Memory Limit: 65536 KB Total Submissions: 3 Accepted: 1 Description 战国时 ...
- 升级项目到.NET Core 2.0,在Linux上安装Docker,并成功部署
概述 容器,顾名思义是用来存放并容纳东西的器皿: 而容器技术伴着Docker的兴起也渐渐的映入大家的眼帘,它是一个抽象的概念,同时也是默默存在世上多年的技术,不仅能使应用程序间完全的隔离,而且还能在共 ...
- 从SVN到Git最强指南
对于软件开发人员来说,版本控制系统他们再熟悉不过了,所谓版本控制系统就是软件项目开发过程中用于储存开发人员所写代码所有修订版本的软件.它的主要目的是实现开发团队并行开发.提高开发效率,对软件开发进程中 ...
- Ubuntu apt-get update 失败
apt-get碰上了"fetch http://--失败", 自带源在国内连接性不好. 解决:改用"阿里云Ubuntu源": https://www.yuren ...
- 设计模式之Iterator模式
STL里的iterator就是应用了iterator模式. 一.什么是迭代模式 Iterator模式也叫迭代模式,是行为模式之一,它把对容器中包含的内部对象的访问委让给外部类,使用Iterator按顺 ...
- 剑指OFFER的跳台阶问题
一只青蛙一次可以跳上1级台阶,也可以跳上2级.求该青蛙跳上一个n级的台阶总共有多少种跳法. (斐波那契数列的变形) F(1)=1;F(2)=2; F(n)=F(n-1)+F(n-2); class S ...
- 011.Adding Search to an ASP.NET Core MVC app --【给程序添加搜索功能】
Adding Search to an ASP.NET Core MVC app 给程序添加搜索功能 2017-3-7 7 分钟阅读时长 作者 本文内容 1.Adding Search by genr ...
- Android图片轮播控件
Android广告图片轮播控件,支持无限循环和多种主题,可以灵活设置轮播样式.动画.轮播和切换时间.位置.图片加载框架等! 使用步骤 Step 1.依赖banner Gradle dependenci ...
- 如何统计iOS产品不同渠道的下载量?
一.前言 在开发过程中,Android可能会打出来很多的包,用于标识不同的商店下载量.原来觉得苹果只有一个商店:AppStore,如何做出不同来源的统计呢?本篇文章就是告诉大家如何做不同渠道来源统计. ...