JavaScript并发模型与Event Loop (转载)
并发模型可视化描述
model.svg
如上图所示,Javascript执行引擎的主线程运行的时候,产生堆(heap)和栈(stack),程序中代码依次进入栈中等待执行,
若执行时遇到异步方法,该异步方法会被添加到用于回调的队列(queue)中【即JavaScript执行引擎的主线程拥有一个执行栈/堆和一个任务队列】。
栈(stack) : 函数调用会形成了一个堆栈帧
堆(heap) : 对象被分配在一个堆中,一个用以表示一个内存中大的未被组织的区域。
队列(queue) : 一个 JavaScript 运行时包含了一个待处理的消息队列。每一个消息都与一个函数相关联。当栈为空时,则从队列中取出一个消息进行处理。这个处理过程包含了调用与这个消息相关联的函数(以及因而创建了一个初始堆栈帧)。
当栈再次为空的时候,也就意味着该消息处理结束。
为了更清晰地描述Event Loop,参考下图的描述:
model.png
首先,我们对图中的一些名词稍加解释:
- queue : 如上文的解释,值得注意的是,除了IO设备的事件(如load)会被添加到queue中,用户操作产生 的事件(如click,touchmove)同样也会被添加到queue中。队列中的这些事件会在主线程的执行栈被清空时被依次读取(队列先进先出,即先被压入队列中的事件会被先执行)。
- callback : 被主线程挂起来的代码,等主线程执行队列中的事件时,事件对应的callback代码就会被执行
【注:因为主线程从"任务队列"中读取事件的过程是循环不断的,因此这种运行机制又称为Event Loop(事件循环)】
下面我们通过setTimeout来看看单线程的JavaScript执行引擎是如何来执行该方法的。
- JavaScript执行引擎主线程运行,产生heap和stack
- 从上往下执行同步代码,log(1)被压入执行栈,因为log是webkit内核支持的普通方法而非WebAPIs的方法,因此立即出栈被引擎执行,输出1
- JavaScript执行引擎继续往下,遇到setTimeout()t异步方法(如图,setTimeout属于WebAPIs),将setTimeout(callback,5000)添加到执行栈
- 因为setTimeout()属于WebAPIs中的方法,JavaScript执行引擎在将setTimeout()出栈执行时,注册setTimeout()延时方法交由浏览器内核其他模块(以webkit为例,是webcore模块)处理
- 继续运行setTimeout()下面的log(3)代码,原理同步骤2
- 当延时方法到达触发条件,即到达设置的延时时间时(5秒后),该延时方法就会被添加至任务队列里。这一过程由浏览器内核其他模块处理,与执行引擎主线程独立
- JavaScript执行引擎在主线程方法执行完毕,到达空闲状态时,会从任务队列中顺序获取任务来执行。
- 将队列的第一个回调函数重新压入执行栈,执行回调函数中的代码log(2),原理同步骤2,回调函数的代码执行完毕,清空执行栈
- JavaScript执行引擎继续轮循队列,直到队列为空
- 执行完毕
console.log(1);
setTimeout(function() {
console.log(2);
},5000);
console.log(3);
//输出结果:
//1
//3
//2复制代码
Macrotasks 和 Microtasks
基本上,一个完整的事件循环模型就讲完了。现在我们来重点关注一下队列。
异步任务分为两种:Macrotasks 和 Microtasks。
- Macrotasks: setTimeout, setInterval, setImmediate, I/O, UI rendering
- Microtasks: process.nextTick, Promises, Object.observe(废弃), MutationObserver
Macrotasks 和 Microtasks有什么区别呢?我们以setTimeout和Promises来举例。
console.log('1');
setTimeout(function() {
console.log('2');
}, 0);
Promise.resolve().then(function() {
console.log('3');
}).then(function() {
console.log('4');
});
console.log('5');
//输出结果:
//1
//5
//3
//4
//2复制代码
原因是Promise中的then方法的函数会被推入 microtasks 队列,而setTimeout的任务会被推入 macrotasks 队列。在每一次事件循环中,macrotask 只会提取一个执行,而 microtask 会一直提取,直到 microtasks 队列清空。
结论如下:
- microtask会优先macrotask执行
- microtasks会被循环提取到执行引擎主线程的执行栈,直到microtasks任务队列清空,才会执行macrotask
【注:一般情况下,macrotask queues 我们会直接称为 task queues,只有 microtask queues 才会特别指明。】
作者:网易考拉前端团队
链接:https://juejin.im/post/59b499a8f265da0656043567
来源:掘金
JavaScript并发模型与Event Loop (转载)的更多相关文章
- javascript运行模式:并发模型 与Event Loop
看了阮一峰老师的JavaScript 运行机制详解:再谈Event Loop和[朴灵评注]的文章,查阅网上相关资料,把自己对javascript运行模式和EVENT loop的理解整理下,不一定对,日 ...
- JavaScript Concurrency model and Event Loop 并发模型和事件循环机制
原文地址:https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop JavaScript 有一个基于 event loop 的 ...
- 一篇文章图文并茂地带你轻松学完 JavaScript 事件循环机制(event loop)
JavaScript 事件循环机制 (event loop) 本篇文章已经默认你有了基础的 ES6 和 javascript语法 知识. 本篇文章比较细致,如果已经对同步异步,单线程等概念比较熟悉的读 ...
- javascript基础修炼(5)—Event Loop(Node.js)
开发者的javascript造诣取决于对[动态]和[异步]这两个词的理解水平. 一. 一道考察异步知识的面试题 题目是这样的,要求写出下面代码的输出: setTimeout(() => { co ...
- javascript的执行机制—Event Loop
既然今天要谈的是javascript的事件循环机制,要理解事件循环,首先要知道事件循环是什么. 我们先从一个例子来看一下javascript的执行顺序. <script> setTimeo ...
- JavaScript 运行机制以及Event Loop(事件循环)
一.JavaScript单线程 众所周知JavaScript是一门单线程语言,也就是说,在同一时间内JS只能做一件事.为什么JavaScript不能有多个线程呢?这样不是能够提高效率吗? JavaSc ...
- JavaScript 的核心机制——event loop(最易懂版)
前言 javascript从诞生之日起就是一门单线程的非阻塞的脚本语言. 非阻塞就是当代码需要进行一项异步任务(无法立刻返回结果,需要花一定时间才能返回的任务,如ajax事件)时,主线程会挂起(pen ...
- [更新]单线程的JS引擎与 Event Loop
先来思考一个问题,JS 是单线程的还是多线程的?如果是单线程,为什么JavaScript能让AJAX异步发送和回调请求,还有setTimeout也看起来像是多线程的?还有non-blocking IO ...
- 从event loop规范探究javaScript异步及浏览器更新渲染时机
异步的思考 event loops隐藏得比较深,很多人对它很陌生.但提起异步,相信每个人都知道.异步背后的“靠山”就是event loops.这里的异步准确的说应该叫浏览器的event loops或者 ...
随机推荐
- codeblock 生成和使用makefile
下载cbp2make 文件名:cbp2make-stl-rev138.tar.gz 里面有个cbp文件用codeblock打开,编译,生成的bin目录下有个执行文件. 使用命令生成Makefile . ...
- 使用JavaMail创建邮件和发送邮件
参考https://www.cnblogs.com/xdp-gacl/p/4216311.html,写的真好,知识在于分享,备份留着看 一.RFC882文档简单说明 RFC882文档规定了如何编写一封 ...
- Spring 回滚事务@Transactional
@Transactional spring 事务注解 默认遇到throw new RuntimeException("...");会回滚 需要捕获的throw new Exce ...
- 初见Hadoop—- 搭建MyEclipse 访问HDFS 上的文件
因公司项目需要,开始接触大数据分析这块知识.网上关于大数据这块的知识还是比较多的.学习了一个礼拜了,再次记录一下,自己的学习过程,希望可以帮助后学者少走一些弯路. 服务端的配置,由于公司项目经理已经配 ...
- C#拷贝一个库的表到另外一个库中(的四种方式)
1.该方法 基本不能用于实际开发中 ,仅供学习参考 public string Copy() { //要复制的表名 string table = "AAAAA"; //构造连接字符 ...
- [UnityShader效果]01.Mask
参考链接: https://blog.csdn.net/akof1314/article/details/50428200 1.Mask.shader // Unity built-in shader ...
- 74.纯 CSS 创作一台 MacBook Pro
原文地址:https://segmentfault.com/a/1190000015568609 HTML code: <div class="macbook"> &l ...
- maven 版本发布添加上时间戳
使用插件添加时间戳 我使用的是spring boot - 2.0.3.RELEASE版本 pom中加入 <!-- 加入这个 就可以直接在配置文件中取到时间戳了,注意: 由于${}方式会被mave ...
- PostgreSQL模式(schema)介绍
一个PostgreSQL数据库集群包含一个或多个已命名数据库.用户和用户组在整个集群范围内是共享的,但是其它数据并不共享.任何与服务器连接的客户都只能访问那个在连接请求里声明的数据库. 注意: 集群中 ...
- turtle画戒指
import turtleturtle.bgcolor('black')turtle.speed(5)turtle.pensize(3)for i in range(1,5): turtle.righ ...