js的事件循环和任务队列
js 异步、栈、事件循环、任务队列
在开发中经常遇到js的异步问题,为了方便理解,记录下来,随时回顾。
- 以下的所有代码都是在浏览器环境下运行
在浏览器中js的运行是依赖浏览器js引擎来解析的,并且是在一定的runtime(运行时)的环境被调用,被执行。由于js引擎是单线程的,所以在执行dom渲染,script引入的时候这些操作是同步的,js引擎会通过 Event Loop 的机制,按顺序把任务放入栈中执行
而在代码中产生的异步代码则是由 runtime 提供的,拥有和Js引擎互不干扰的线程
栈
栈是一个后进先出的一种数据结构,执行起来效率比较高,往往堆里存放着一些对象。而栈中则存放着一些基础类型变量以及对象的指针,在函数调用的时候,会产生函数的执行栈,也叫执行上下文,这个执行环境中存在着这个函数的私有作用域,上层作用域的指向,函数的参数,这个作用域中定义的变量以及这个作用域的this对象。 而当一系列函数被依次调用的时候,因为js是单线程的,同一时间只能执行一个函数,于是这些函数被排队在一个单独的地方。这个地方被称为执行栈。
当一个脚本第一次执行的时候,js引擎会解析这段代码,并将其中的同步代码按照执行顺序加入执行栈中,然后从头开始执行。如果当前执行的是一个方法,那么js会向执行栈中添加这个方法的执行环境,然后进入这个执行环境继续执行其中的代码。当这个执行环境中的代码 执行完毕并返回结果后,js会退出这个执行环境并把这个执行环境销毁,回到上一个方法的执行环境。。这个过程反复进行,直到执行栈中的代码全部执行完毕。
总的来说
- 栈存放着一些基础类型变量以及对象的指针
- 当代码执行的时候,同步代码按照执行顺序开始执行
- 当代码执行的时候,碰到函数,引擎会在栈里产生这个函数执行栈,也叫执行上下文。
- 当代码执行到函数的时候,会进入这个执行环境继续执行其中的代码,反复进行,全部执行完
任务队列
Js 中,有两类任务队列:宏任务队列(macro tasks)和微任务队列(micro tasks)。宏任务队列可以有多个,微任务队列只有一个
- 宏任务:script(全局任务), setTimeout, setInterval, setImmediate, I/O, UI rendering.
- 微任务:process.nextTick (node.js中进程相关的对象), Promise, Object.observer, MutationObserver。
在浏览器的 Event Loop机制中,整个流程可以用张图来表示一下:
这张图中可以看到:
- 微任务队列(micro tasks)只会有一个
- 宏任务队列(macro tasks)可以有多个
- click ajax 等回调方法都会进入到宏任务队列(macro tasks)中,当然也包括上面的
而在浏览器的Event Loop机制运行时,宏任务队列(macro tasks)和微任务队列(micro tasks)的关系,关于这点详见(关系)
- 宏任务按顺序执行,且浏览器在每个宏任务之间渲染页面
- 所有微任务也按顺序执行,且在以下场景会立即执行所有微任务
- 每个回调之后且js执行栈中为空。
- 每个宏任务结束后。
而在 NodeJs 的 Event Loop 遵循的是 libuv
这个库是node作者自己写的,内部实现了一整套的异步io机制(内部使用c++和js实现),使我们开发异步程序变得简单,因为这个原因导致了一些js解析和浏览器的会不一样。
NodeJs 的运行是这样的:
- 初始化 Event Loop
- 执行您的主代码。这里同样,遇到异步处理,就会分配给对应的队列。直到主代码执行完毕。
- 执行主代码中出现的所有微任务:先执行完所有nextTick(),然后在执行其它所有微任务。
- 开始 Event Loop
当每个阶段执行完毕后,都会执行所有微任务(先 nextTick,后其它),然后再进入下一个阶段。
最后我们来段代码彻底解析下两类任务队列在运行时的逻辑
console.log('1');
setTimeout(function() {
console.log('2');
process.nextTick(function() {
console.log('3');
})
new Promise(function(resolve) {
console.log('4');
resolve();
}).then(function() {
console.log('5')
})
})
process.nextTick(function() {
console.log('6');
})
new Promise(function(resolve) {
console.log('7');
resolve();
}).then(function() {
console.log('8')
})
setTimeout(function() {
console.log('9');
process.nextTick(function() {
console.log('10');
})
new Promise(function(resolve) {
console.log('11');
resolve();
}).then(function() {
console.log('12')
})
})
结合上面讲的逻辑 可以分析一波得出最后答案是1,7,6,8,2,4,3,5,9,11,10,12
js的事件循环和任务队列的更多相关文章
- JS 的线程、事件循环、任务队列简介
JS 是单线程的,但是却能执行异步任务,这主要是因为 JS 中存在事件循环(Event Loop)和任务队列(Task Queue). 事件循环:JS 会创建一个类似于 while (true) 的循 ...
- JS 事件循环机制 - 任务队列、web API、JS主线程的相互协同
一.JS单线程.异步.同步概念 从上一篇说明vue nextTick的文章中,多次出现“事件循环”这个名词,简单说明了事件循环的步骤,以便理解nextTick的运行时机,这篇文章将更为详细的分析下事件 ...
- JS JavaScript事件循环机制
区分进程和线程 进程是cpu资源分配的最小单位(系统会给它分配内存) 不同的进程之间是可以同学的,如管道.FIFO(命名管道).消息队列 一个进程里有单个或多个线程 浏览器是多进程的,因为系统给它的进 ...
- JS-线程、事件循环、任务队列
JS 是单线程的,但是却能执行异步任务,这主要是因为 JS 中存在事件循环(Event Loop)和任务队列(Task Queue). 事件循环: JS 会创建一个类似于 while (true) 的 ...
- 浏览器中 JS 的事件循环机制
目录 事件循环机制 宏任务与微任务 实例分析 参考 1.事件循环机制 浏览器执行JS代码大致可以分为三个步骤,而这三个步骤的往复构成了JS的事件循环机制(如图). 第一步:主线程(JS引擎线程)中执行 ...
- js的事件循环绑定和jQuery的隐式迭代
js的事件循环绑定和jQuery的隐式迭代 js事件循环绑定 jQuery隐式迭代 先举一个例子:给定一个ul,点击列表内的每一个li元素,使它的背景色变红,下边分别用js代码和jQuery实现. & ...
- Node.js:事件循环
ylbtech-Node.js:事件循环 1.返回顶部 1. Node.js 事件循环 Node.js 是单进程单线程应用程序,但是通过事件和回调支持并发,所以性能非常高. Node.js 的每一个 ...
- Node.js 的事件循环机制
目录 微任务 事件循环机制 setImmediate.setTimeout/setInterval 和 process.nextTick 执行时机对比 实例分析 参考 1.微任务 在谈论Node的事件 ...
- JS:事件循环机制、调用栈以及任务队列
点击查看原文 写在前面 js里的事件循环机制十分有趣.从很多面试题也可以看出来,考察简单的setTimeout也就是考察这个机制的. 在之前,我只是简单地认为由于函数执行很快,setTimeout执行 ...
随机推荐
- 2020HDU多校第三场 1005 Little W and Contest
Little W and Contest Time Limit: 2000/2000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/O ...
- Python自动化运维:技术与最佳实践 PDF高清完整版|网盘下载内附地址提取码|
内容简介: <Python自动化运维:技术与最佳实践>一书在中国运维领域将有“划时代”的重要意义:一方面,这是国内第一本从纵.深和实践角度探讨Python在运维领域应用的著作:一方面本书的 ...
- statsmodels 示例
Statsmodels 示例 https://www.statsmodels.org/stable/examples/index.html
- Python continue语句
Python continue语句: 当执行到 continue 语句时,将不再执行本次循环中 continue 语句接下来的部分,而是继续下一次循环. lst = [7,8,9,4,5,6] for ...
- 使用 MySQLi 和 PDO 向 MySQL 插入多条数据
PHP MySQL 插入多条数据 使用 MySQLi 和 PDO 向 MySQL 插入多条数据 mysqli_multi_query() 函数可用来执行多条SQL语句. 以下实例向 "MyG ...
- Python File close() 方法
概述 close() 方法用于关闭一个已打开的文件.高佣联盟 www.cgewang.com 关闭后的文件不能再进行读写操作, 否则会触发 ValueError 错误. close() 方法允许调用多 ...
- luogu P4606 [SDOI2018]战略游戏
LINK:战略游戏 一道很有价值的题目.这道题 一张无向联通图 每次询问给出K个关键点 问摧毁图中哪个点可以使得这K个关键的两两之间有一对不能联通 去掉的这个点不能是关键点 求方案数. 可以发现 当K ...
- HA模式下的java api访问要点
在非HA架构的HDFS中,客户端要通过java接口调用HDFS时一般是在JobRunner的类中按照下面的方式: 因为nodename只有一个节点所以会在代码中显式的指明要连接哪一个节点:但是在HA模 ...
- Docker管理工具之portainer
参考:https://www.cnblogs.com/frankdeng/p/9686735.html 1. 查询portainer镜像 命令:docker search portainer 实例: ...
- 基于asp.net core 从零搭建自己的业务框架(二)
前言 对于项目的迭代,如何降低复杂性的要求高于性能以及技术细节的 一个易用的项目,才能迭代到比拼性能,最后拼刺刀的阶段 传统单体项目,都是传统三层,直接请求响应的模式,这类称为Rpc模式,易用性上非常 ...