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或者 ...
随机推荐
- yidun验证码
from PIL import Imagefrom selenium import webdriverfrom selenium.webdriver import ActionChainsfrom s ...
- 批量查杀该死的VBscript “svchost.exe” 脚本挂马
今天写代码突然发现HTML文件最后多了一段VBscript代码: <SCRIPT Language=VBScript><!-- DropFileName = "svchos ...
- 【人工智能】从零开始学好人工智能,AI知识体系和框架
写在前面: 最近公司的业务方向开始向AI方向改变(人工智能+文娱),但是现阶段AI方面的知识还没有储备,所以作为测试,也开始学习这方面的知识,不掉队. 知识储备: 1.阶段一-高等数学 高 ...
- 【python】python中的enumerate()函数【笔记】
结合实例来理解比较好,网上找了一下这个enumerate用法,自己也记录一下加深印象 看一下相关链接: 链接1:http://www.cnblogs.com/danielStudy/p/6576040 ...
- 关于Hibernate和Strtus2的xml提示问题
话不多说,上图 1.Windom 2.preferences 3.搜索框搜索xml catalog 点击Add 4.导入约束(具体操作图上1.2.3)
- 解决Windows下mysql无法启动1067错误
解决过程 查看服务发现mysql未启动 用cmd命令行启动提示启动失败 错误代码1067 打开时间查看器发现mysql错误记录信息为Fatal error: Can't open and lock ...
- js学习2
1.打开新窗体 -window.open([URL], [窗口名称], [参数字符串]) - 窗口名称: _blank:在新窗口显示目标网页 _self:在当前窗口显示目标网页 _top:框架网页中在 ...
- HTML5 前端将 dom 元素转化为 Word,EXCEL 或者图片 并实现下载
< 一 > word 1,依赖于 jquery.html.word.js 插件 => https://blog-static.cnblogs.com/files/lovling/ ...
- 4Linux环境变量、Vim、Shell脚本
环境变量 命令在Linux中的执行分为4个步骤: 1.以路径的形式来执行 2.命令的别名形式来执行,alias 新命令=“原始命令”,新命令与原始命令互不冲突,可以同时使用,重启失效,修改/etc/p ...
- ubuntu环境下安装docker遇到的坑
ubuntu安装docker的前提条件是: 1. Linux 的内核版本在 3.10 或以上: 2. linux 内核要开启 cgroup 和 namespace 功能 可以执行命令:uname –a ...