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代码的线程只有一个.不妨叫它主线程. 但是实际上还存在其他 ...
随机推荐
- HTML <img>标签 创建图像映射
初级前端一枚 下面代码是在图片上创建图像映射 自己整理了下 做个笔记 希望也可以帮助后来学习的朋友! <map name="planetmap"> <area s ...
- 用Python处理实验数据
开篇语 近来忙于考试以及应付专业课,基本很少写简书了.昨晚攻坚了三个学生工作的任务(妈妈的吻.好久没有这么疯狂工作了.还是很爽的哦!) 今天难得清静,虽然上课还是沉浸于完成任务的放纵式玩手机中,但是也 ...
- 转载的log4cplus使用指南
以下转载的log4cplus使用指南的版本可能不是最新,仅作参考了解.应以最新安装包中的示例代码为准. 目 录1 Log4cplus简介 52 安装方法 53 主要类说明 64 ...
- java 内存模型的理解
之前一直在实习,博客停写了一段时间,现在秋招开始了,所以辞职回来专心看书,同时将每天的收获以博客的形式记录下来.最近在看jvm相关的书籍,下面对面试中问得最多的部分--java 内存模型. 本篇博客大 ...
- ASP.NET Core 快速入门【第二弹-实战篇】
上篇讲了asp.net core在linux上的环境部署.今天我们将做几个小玩意实战一下.用到的技术和工具有mysql.websocket.AngleSharp(爬虫html解析).nginx多站点部 ...
- HTML 文本格式化实例 超链接
HTML 文本格式化实例 1.文本格式化 <b>加粗文字</b> <strong>加重语气</strong> <big>dingyi< ...
- 第7章 DNS & bind从基础到深入
本文目录: 7.1 DNS必懂基础 7.1.1 域的分类 7.1.2 主机名.域名.FQDN 7.1.3 域的分层授权 7.1.4 DNS解析流程 7.2 DNS术语 7.2.1 递归查询和迭代查询 ...
- python编码问题一点通
一.了解字符编码的知识储备 1. 文本编辑器存取文件的原理(nodepad++,pycharm,word) 打开编辑器就打开了启动了一个进程,是在内存中的,所以在编辑器编写的内容也都是存放与内存中的, ...
- Response乱码时的处理方法
有时候我们看到Response中的HTML是乱码的, 这是因为HTML被压缩了, 我们可以通过两种方法去解压缩. 步骤:方法一:点击红框内容"Response body is encoude ...
- JMeter元件的作用域和执行顺序
元件的作用域 配置元件:会影响其作用范围内的所有元件,作用范围是最大的,只要创建就对所有元件起作用. 前置处理器:在其作用范围内的每一个Sample元件之前执行: 定时器:对其作用范围内的每一个Sam ...