并发模型可视化描述

model.svg

如上图所示,Javascript执行引擎的主线程运行的时候,产生堆(heap)和栈(stack),程序中代码依次进入栈中等待执行,

若执行时遇到异步方法,该异步方法会被添加到用于回调的队列(queue)中【即JavaScript执行引擎的主线程拥有一个执行栈/堆和一个任务队列】。

栈(stack) : 函数调用会形成了一个堆栈帧
堆(heap) : 对象被分配在一个堆中,一个用以表示一个内存中大的未被组织的区域。
队列(queue) : 一个 JavaScript 运行时包含了一个待处理的消息队列。每一个消息都与一个函数相关联。

当栈为空时,则从队列中取出一个消息进行处理。这个处理过程包含了调用与这个消息相关联的函数(以及因而创建了一个初始堆栈帧)。

当栈再次为空的时候,也就意味着该消息处理结束。

为了更清晰地描述Event Loop,参考下图的描述:

model.png

首先,我们对图中的一些名词稍加解释

  1. queue : 如上文的解释,值得注意的是,除了IO设备的事件(如load)会被添加到queue中,用户操作产生 的事件(如click,touchmove)同样也会被添加到queue中。队列中的这些事件会在主线程的执行栈被清空时被依次读取(队列先进先出,即先被压入队列中的事件会被先执行)。
  2. callback : 被主线程挂起来的代码,等主线程执行队列中的事件时,事件对应的callback代码就会被执行

【注:因为主线程从"任务队列"中读取事件的过程是循环不断的,因此这种运行机制又称为Event Loop(事件循环)】

下面我们通过setTimeout来看看单线程的JavaScript执行引擎是如何来执行该方法的。

  1. JavaScript执行引擎主线程运行,产生heap和stack
  2. 从上往下执行同步代码,log(1)被压入执行栈,因为log是webkit内核支持的普通方法而非WebAPIs的方法,因此立即出栈被引擎执行,输出1
  3. JavaScript执行引擎继续往下,遇到setTimeout()t异步方法(如图,setTimeout属于WebAPIs),将setTimeout(callback,5000)添加到执行栈
  4. 因为setTimeout()属于WebAPIs中的方法,JavaScript执行引擎在将setTimeout()出栈执行时,注册setTimeout()延时方法交由浏览器内核其他模块(以webkit为例,是webcore模块)处理
  5. 继续运行setTimeout()下面的log(3)代码,原理同步骤2
  6. 当延时方法到达触发条件,即到达设置的延时时间时(5秒后),该延时方法就会被添加至任务队列里。这一过程由浏览器内核其他模块处理,与执行引擎主线程独立
  7. JavaScript执行引擎在主线程方法执行完毕,到达空闲状态时,会从任务队列中顺序获取任务来执行。
  8. 将队列的第一个回调函数重新压入执行栈,执行回调函数中的代码log(2),原理同步骤2,回调函数的代码执行完毕,清空执行栈
  9. JavaScript执行引擎继续轮循队列,直到队列为空
  10. 执行完毕
    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 队列清空。
结论如下:

  1. microtask会优先macrotask执行
  2. microtasks会被循环提取到执行引擎主线程的执行栈,直到microtasks任务队列清空,才会执行macrotask

【注:一般情况下,macrotask queues 我们会直接称为 task queues,只有 microtask queues 才会特别指明。】

作者:网易考拉前端团队
链接:https://juejin.im/post/59b499a8f265da0656043567
来源:掘金

JavaScript并发模型与Event Loop (转载)的更多相关文章

  1. javascript运行模式:并发模型 与Event Loop

    看了阮一峰老师的JavaScript 运行机制详解:再谈Event Loop和[朴灵评注]的文章,查阅网上相关资料,把自己对javascript运行模式和EVENT loop的理解整理下,不一定对,日 ...

  2. JavaScript Concurrency model and Event Loop 并发模型和事件循环机制

    原文地址:https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop JavaScript 有一个基于 event loop 的 ...

  3. 一篇文章图文并茂地带你轻松学完 JavaScript 事件循环机制(event loop)

    JavaScript 事件循环机制 (event loop) 本篇文章已经默认你有了基础的 ES6 和 javascript语法 知识. 本篇文章比较细致,如果已经对同步异步,单线程等概念比较熟悉的读 ...

  4. javascript基础修炼(5)—Event Loop(Node.js)

    开发者的javascript造诣取决于对[动态]和[异步]这两个词的理解水平. 一. 一道考察异步知识的面试题 题目是这样的,要求写出下面代码的输出: setTimeout(() => { co ...

  5. javascript的执行机制—Event Loop

    既然今天要谈的是javascript的事件循环机制,要理解事件循环,首先要知道事件循环是什么. 我们先从一个例子来看一下javascript的执行顺序. <script> setTimeo ...

  6. JavaScript 运行机制以及Event Loop(事件循环)

    一.JavaScript单线程 众所周知JavaScript是一门单线程语言,也就是说,在同一时间内JS只能做一件事.为什么JavaScript不能有多个线程呢?这样不是能够提高效率吗? JavaSc ...

  7. JavaScript 的核心机制——event loop(最易懂版)

    前言 javascript从诞生之日起就是一门单线程的非阻塞的脚本语言. 非阻塞就是当代码需要进行一项异步任务(无法立刻返回结果,需要花一定时间才能返回的任务,如ajax事件)时,主线程会挂起(pen ...

  8. [更新]单线程的JS引擎与 Event Loop

    先来思考一个问题,JS 是单线程的还是多线程的?如果是单线程,为什么JavaScript能让AJAX异步发送和回调请求,还有setTimeout也看起来像是多线程的?还有non-blocking IO ...

  9. 从event loop规范探究javaScript异步及浏览器更新渲染时机

    异步的思考 event loops隐藏得比较深,很多人对它很陌生.但提起异步,相信每个人都知道.异步背后的“靠山”就是event loops.这里的异步准确的说应该叫浏览器的event loops或者 ...

随机推荐

  1. 恭喜PBD终于有了自己的物理解释和模型

    之前的position based dynamic 总给人一种野路子的感觉,没有物理意义,没有对应的物理模型一切基于几何的方法. 感觉就是犀稀里哗啦将一堆堆约束按梯度方向迭代解算. 最新muller的 ...

  2. json_encode($b, JSON_FORCE_OBJECT) 可以强制转换成对象

    最近在为移动端的项目提供接口,数据格式都为json,不过在过程中遇到一个小问题,代码如下: 情况一: $tmp = array('a','b','c'); echo json_encode($tmp) ...

  3. nginx+ftp服务器搭建简易文件服务器

    在做一些小项目和学习项目过程中,学习了通过 nginx 和 FTP 搭建小型文件服务器,记录下: 1.环境 电脑:acer 操作系统:windows 10 ftp服务器 2.下载 nginx, 通过双 ...

  4. Python全栈开发记录_第四篇(集合、函数等知识点)

    知识点1:深拷贝和浅拷贝 非拷贝(=赋值:数据完全共享,内存地址一样,修改一个另一个也变化) 浅拷贝:数据半共享(复制其数据独立内存存放,但是只拷贝成功第一层)像[[1,2],3,4]如果修改列表中列 ...

  5. openstack创建虚拟流程、各组件介绍

    登录界面或命令行通过RESTful API向keystone获取认证信息. keystone通过用户请求认证信息,并生成auth-token返回给对应的认证请求. 界面或命令行通过RESTful AP ...

  6. LeetCode 101. Symmetric Tree 判断对称树 C++

    Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center). For e ...

  7. Mac 端配置 Lua 环境

    一.设计目的 Lua 是一种轻量级的脚本语言,其目的是为了嵌入到程序中,从而为程序提供灵活的扩展和定制功能. 二.特性 轻量级:编译后仅仅 100 余K,可以很方便的嵌入到程序中. 可扩展:Lua 提 ...

  8. vue cli 3

    介绍 Vue CLI 是一个基于 Vue.js 进行快速开发的完整系统 通过 @vue/cli 搭建交互式的项目脚手架. 通过 @vue/cli + @vue/cli-service-global 快 ...

  9. v-charts 第一次亲密接触

    v-charts是什么鬼 v-charts是饿了么团队开源的一个图表库,vue+echarts开发.用element-ui直接集成echarts有些费劲,而v-charts已经封装成vue组件,可以直 ...

  10. android studio 模拟器无法联网的解决方法

    本人环境 win10 64位+ android studio  自带的模拟器 1.首先把模拟器打开,然后需要把SDK文件夹下的platform-tools添加到系统变量中(此目录一定要不要弄错). 2 ...