JavaScript 异步、栈、事件循环、任务队列
概览
我们经常会听到引擎和runtime,它们的区别是什么呢?
- 引擎:解释并编译代码,让它变成能交给机器运行的代码(runnable commands)。
- runtime:就是运行环境,它提供一些对外接口供Js调用,以跟外界打交道,比如,浏览器环境、Node.js环境。不同的runtime,会提供不同的接口,比如,在 Node.js 环境中,我们可以通过
require
来引入模块;而在浏览器中,我们有window
、 DOM。
Js引擎是单线程的,如上图中,它负责维护任务队列,并通过 Event Loop 的机制,按顺序把任务放入栈中执行。而图中的异步处理模块,就是 runtime 提供的,拥有和Js引擎互不干扰的线程。接下来,我们会细说图中的:栈和任务队列
栈
现在,我们要运行下面这段代码:
function bar() {
console.log(1);
}
function foo() {
console.log(2);
far();
}
setTimeout(() => {
console.log(3)
});
foo();
它在栈中的入栈、出栈过程,如下图:
任务队列
Js 中,有两类任务队列:宏任务队列(macro tasks)和微任务队列(micro tasks)。宏任务队列可以有多个,微任务队列只有一个。那么什么任务,会分到哪个队列呢?
- 宏任务:script(全局任务), setTimeout, setInterval, setImmediate, I/O, UI rendering.
- 微任务:process.nextTick, Promise, Object.observer, MutationObserver.
我们上面讲到,当stack空的时候,就会从任务队列中,取任务来执行。共分3步:
- 取一个宏任务来执行。执行完毕后,下一步。
- 取一个微任务来执行,执行完毕后,再取一个微任务来执行。直到微任务队列为空,执行下一步。
- 更新UI渲染。
Event Loop 会无限循环执行上面3步,这就是Event Loop的主要控制逻辑。其中,第3步(更新UI渲染)会根据浏览器的逻辑,决定要不要马上执行更新。毕竟更新UI成本大,所以,一般都会比较长的时间间隔,执行一次更新。
从执行步骤来看,我们发现微任务,受到了特殊待遇!我们代码开始执行都是从script(全局任务)开始,所以,一旦我们的全局任务(属于宏任务)执行完,就马上执行完整个微任务队列。看个例子:
console.log('script start'); Promise.resolve().then(() => {
上面之所以加50ms的阻塞,是因为
console.log('p 1');
}); setTimeout(() => {
console.log('setTimeout');
}, 0); var s = new Date();
while(new Date() - s < 50); // 阻塞50ms Promise.resolve().then(() => {
console.log('p 2');
}); console.log('script ent'); /*** output ***/ // one macro task
script start
script ent // all micro tasks
p 1
p 2 // one macro task again
setTimeoutsetTimeout
的 delayTime 最少是 4ms. 为了避免认为setTimeout
是因为4ms的延迟而后面才被执行的,我们加了50ms阻塞。在微任务中,process.nextTick
是一个特殊的任务,它会被直接插入到微任务的队首(当然了,多个process.nextTick
之间也是先入先出的),优先级最高。 来源:https://segmentfault.com/a/1190000011198232
JavaScript 异步、栈、事件循环、任务队列的更多相关文章
- 总结:JavaScript异步、事件循环与消息队列、微任务与宏任务
本人正在努力学习前端,内容仅供参考.由于各种原因(不喜欢博客园的UI),大家可以移步我的github阅读体验更佳:传送门,喜欢就点个star咯,或者我的博客:https://blog.tangzhen ...
- (转)总结:JavaScript异步、事件循环与消息队列、微任务与宏任务
前言 Philip Roberts 在演讲 great talk at JSConf on the event loop 中说:要是用一句话来形容 JavaScript,我可能会这样: “JavaSc ...
- 深入理解javascript中的事件循环event-loop
前面的话 本文将详细介绍javascript中的事件循环event-loop 线程 javascript是单线程的语言,也就是说,同一个时间只能做一件事.而这个单线程的特性,与它的用途有关,作为浏览器 ...
- JavaScript中的事件循环机制跟函数柯里化
一.事件循环机制的理解 test();//按秒输出5个5 function test() { for (var i = 0; i < 5; i++) { setTimeout(() => ...
- 破阵九解:Node和浏览器之事件循环/任务队列/异步顺序/数据结构
前言 本文内容比较长,请见谅.如有评议,还请评论区指点,谢谢大家! >> 目录 开门见山:Node和浏览器的异步执行顺序问题 两种环境下的宏任务和微任务(macrotask &&a ...
- JavaScript:彻底理解同步、异步和事件循环(Event Loop) (转)
原文出处:https://segmentfault.com/a/1190000004322358 一. 单线程 我们常说"JavaScript是单线程的". 所谓单线程,是指在JS ...
- JavaScript:彻底理解同步、异步和事件循环(Event Loop)
一. 单线程 我们常说"JavaScript是单线程的". 所谓单线程,是指在JS引擎中负责解释和执行JavaScript代码的线程只有一个.不妨叫它主线程. 但是实际上还存在其他 ...
- 让你高效的理解JavaScript中的同步、异步和事件循环
"同步请求","异步请求"相信这两词在程序猿的世界中频频出现,到底是词性的妖娆,还是撸代码的基础要求,下面直接分享本人学习的好东西,保证让你深入浅出,爽得不要不 ...
- [转] JavaScript:彻底理解同步、异步和事件循环(Event Loop)
一. 单线程 我们常说“JavaScript是单线程的”. 所谓单线程,是指在JS引擎中负责解释和执行JavaScript代码的线程只有一个.不妨叫它主线程. 但是实际上还存在其他的线程.例如:处理A ...
- JavaScript中的事件循环
JavaScript是单线程单并发语言 单线程:主程序只有一个线程,即同一时间片段内其只能执行单个任务. 引发的问题: 单线程,意味着任务都需要排队,前一个任务结束,才会执行后一个任务.若前一个任务耗 ...
随机推荐
- Spring Boot从入门到精通(六)集成Redis实现缓存机制
Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言 ...
- 7-8 jmu-python-从列表中删除元素 (15 分)
删除列表中所有符合条件的值. 输入格式: 输入n,代表要测试n次.每次测试:首先,输入1行字符串(字符串内的元素使用空格分隔)然后,输入要删除的元素x. 输出格式: 输出删除元素x后的每行字符串.如果 ...
- 浏览器渲染流程&Composite(渲染层合并)简单总结
梳理浏览器渲染流程 首先简单了解一下浏览器请求.加载.渲染一个页面的大致过程: DNS 查询 TCP 连接 HTTP 请求即响应 服务器响应 客户端渲染 这里主要将客户端渲染展开梳理一下,从浏览器器内 ...
- 关于integer overflow错误
前端突然报了integer overflow错误,int类型溢出也就是数字超过了int类型,一看很懵逼,查看后台日期发现是在Math.toIntExact()方法报错 那么我们看下方法内部代码: /* ...
- Linux系统简单文件操作命令
项目 内容 作业课程归属 班级课程链接 作业要求 作业要求链接 学号-姓名 17041419-刘金林 作业学习目标 1)学习Linux的基本操作命令:2)在终端上运用命令行去实现基本文件操作 1.查看 ...
- Redis系列二 - 数据结构
前言 redis作为我们开发的一大神器,我们接触肯定不会少,但是很多同学也许只会存储String类型的值,这是非常不合理的.在这里,将带大家认识Redis的5中数据结构. 1.问:Redis有那些数据 ...
- Simulink仿真入门到精通(十四) Simulink自定义环境
14.1 Simulink环境自定义功能 sl_sustomization.m函数是Simulink提供给用户使用MATLAB语言自定义Simulink标准人机界面的函数机制.若sl_sustomiz ...
- touch事件中的touches、targetTouches和changedTouches
touches: 当前屏幕上所有触摸点的列表; targetTouches: 当前对象上所有触摸点的列表; changedTouches: 涉及当前(引发)事件的触摸点的列表; 通过一个例子来区分一下 ...
- 项目部署Django+celery+redis
celery介绍 1.celery应用举例 1.Celery 是一个 基于python开发的分布式异步消息任务队列,通过它可以轻松的实现任务的异步处理, 如果你的业务场景中需要用到异步任务,就可以 ...
- JAVA为什么不能通过构造函数传参来设置数组长度。
今天我们来说说 JAVA通过构造函数传递的参数来设置数组长度的问题. 问题在于我们没有明确知晓JVM的运行顺序.在new对象的时候,先调用构造函数,但是并没有将执行构造函数的代码,随机之后就初始化了 ...