导读:学过 JavaScript(下文简称 JS) 的都知道它是一门单线程的、非阻塞的脚本语言。单线程意味着,JS 代码在执行的任何时候,都只有一个主线程来处理所有的任务,这也就意味着 JS 无法进行多线程编程,但是 JS 当中却有着无处不在的异步概念,我们如何理解呢?理解异步和非阻塞靠的就是 Event Loop(事件循环),本文就围绕 JS 线程、同步异步、任务队列等方面讲解事件循环(Event Loop)。

文|倪萌

网易云信前端开发工程师

JS 线程

为了我们更方便容易了解事件循环,在此之前我们先简单了解下什么叫做 JS 线程。如浏览器的渲染进程是多线程的,主要有以下几个线程:

  • JS 引擎线程(主线程):负责解析 JS 脚本,运行代码。

  • GUI 渲染线程:负责渲染浏览器界面,解析 HTML、CSS、构 DOM 树和 RenderObject 树,布局和绘制等,当界面需要重绘(Repaint)或由于某种操作引发回流 (reflow) 时,该线程就会执行。

  • 定时器触发线程 (setTimeout):浏览器定时计数器并不是由 JS 引擎计数的,因为 JS 引擎是单线程的, 如果处于阻塞线程状态就会影响记计时的准确,因此通过单独线程来计时并触发定时,在计时完毕后,添加到事件队列中,等待 JS 引擎空闲后执行。

  • http 请求线程(ajax):XMLHttpRequest 连接后,通过浏览器新开一个线程请求,当检测到状态变更时,如果同时设置有回调函数,异步线程就产生状态变更事件,将这个回调再放入事件队列中,再由 JS 引擎执行。

  • 浏览器事件触发线程 (onclick):归属于浏览器而不是 JS 引擎,用来控制事件循环,可以这么理解:JS 引擎自己都忙不过来,需要浏览器另开线程协助。

  • 主线程和渲染线程互斥 :JS 引擎线程与 GUI 渲染线程是互斥的,当 JS 引擎执行时 GUI 线程会被挂起(相当于被冻结了),GUI 更新会被保存在一个队列中等到 JS 引擎空闲时立即被执行。

浏览器内核

  • EventLoop 轮询处理线程:我们可以把它理解为一个中介,在主线程、异步线程与消息队列三者之间进行交流与沟通。如下图所示:从主线程那里顺时针的看,整个的流程是循环往复的。只有当主线程的同步代码都执行完了,才会去队列里看看还有什么要执行的。

主线程把 setTimeout、ajax、dom.onclick 分别给三个线程,他们之间有些不同。

1、对于 setTimeout 代码,定时器触发线程在接收到代码时就开始计时,时间到了将回调函数扔进消息队列。

2、对于 ajax 代码,http 异步线程立即发起 http 请求,请求成功后将回调函数扔进消息队列。

3、对于 dom.onclick,浏览器事件线程会先监听 dom,直到 dom 被点击了,才将回调函数扔进消息队列。

同步与异步

JS 分为同步任务和异步任务:

  • 同步任务:立即执行的任务队列,比如一个简单的函数;

  • 异步任务:请求接口发送 ajax,发送 promise,或时间计时器等等;

任务队列(Event Queue)

什么是任务队列呢?可以理解为一个静态的队列存储结构,遵循先进先出原则:同步任务会立刻执行,进入到主线程当中;异步任务会被放到任务队列(Event Queue)当中。

宏任务队列和微任务队列

宏任务(MacroTask):整体代码 Script、UI 渲染、setTimeout、setInterval、setImmediate(Node.js 环境)。

微任务(MicroTask):Promise.then()、catch、finally。

不同点:event loop 里 MacroTask 队列可能有多个,MicroTask 队列只有一个。

MicroTask 优先于 MacroTask 执行,所以如果有需要优先执行的逻辑,放入 MicroTask 队列会比 MacroTask 更早的被执行。

下面几个代码例子可以让我们充分的了解各个任务之间的执行顺序:

执行栈

MacroTask 和 MicroTask 都是推入栈中执行的。JS 是单线程,也就是说只有一个主线程,主线程有一个栈,每一个函数执行的时候,都会生成新的执行上下文,执行上下文会包含一些当前函数的参数、局部变量之类的信息,它会被推入栈中,正在执行的上下文始终处于栈的顶部。当函数执行完后,它的执行上下文会从栈弹出。

总结

同步和异步任务分别进入不同的执行环境, 先执行同步任务,把异步任务放入循环队列当中,等待同步任务执行完,再执行队列中的异步任务。异步任务先执行微观任务,再执行宏观任务。一直这样循环,反复执行,就是我们说的 Event Loop (事件循环)。

事件循环是 JS 这门语言中非常重要且基础的概念。让我们可以清楚的了解事件循环的执行顺序和每一个阶段的特点,可以使我们对一段异步代码的执行顺序有一个清晰的认识,从而减少代码运行的不确定性。合理的使用各种延迟事件的方法,有助于代码更好的按照其优先级去执行。

如果在阅读期间您发现了文章中的一些问题,欢迎在留言中提出,感谢您阅读此文章。

 作者介绍 

倪萌,网易云信 web 前端开发工程师,目前在从事云信金融线业务相关开发工作。

 相关阅读推荐 

  • 技术系列课回顾 | 网易云信变声技术之变调不变速算法

  • 技术干货 | C++20 四大特性之一:Module 特性详解

  • 技术实践 | 网易云信视频转码提速之分片转码

技术干货 | JavaScript 之事件循环(Event Loop)相关推荐

  1. JavaScript 异步执行的学习笔记 - 什么是事件循环 Event loop?

    原文 使用像 JavaScript 这样的语言进行编程时,最重要但也经常被误解的部分之一是如何表达和操作一段需要某段时间才能完成执行的程序行为. 这不仅仅是从 for 循环开始到 for 循环结束发生 ...

  2. php event loop,理解javascript中的事件循环(Event Loop)

    背景 在研究js的异步的实现方式的时候,发现了JavaScript 中的 macrotask 和 microtask 的概念.在查阅了一番资料之后,对其中的执行机制有所了解,下面整理出来,希望可以帮助 ...

  3. JAVA script 循环 图片_深入分析JavaScript 事件循环(Event Loop)

    事件循环(Event Loop),是每个JS开发者都会接触到的概念,但是刚接触时可能会存在各种疑惑. 众所周知,JS是单线程的,即同一时间只能运行一个任务.一般情况下这不会引发问题,但是如果我们有一个 ...

  4. python事件循环_简单了解一下事件循环(Event Loop)

    关于我 一个有思想的程序猿,终身学习实践者,目前在一个创业团队任team lead,技术栈涉及Android.Python.Java和Go,这个也是我们团队的主要技术栈. Github:https:/ ...

  5. 面试率 90% 的JS事件循环Event Loop,看这篇就够了!! !

    面试率 90% 的JS事件循环Event Loop,看这篇就够了!! ! 事件循环(Event Loop)大家应该并不陌生,它是前端极其重要的基础知识.在平时的讨论或者面试中也是一个非常高频的话题. ...

  6. JavaScript基础:浅聊事件循环(Event LooP)以及微任务,宏任务,DOM渲染

    一直说JavaScript是单线程的执行的(当然也可以通过其它其它的方式异步,本篇暂时不聊). 内核的组成 首先聊一下浏览器的内核组成部分,当然下面也不是全部,而只是说一些常见的. 主线线程 js引擎 ...

  7. JavaScipt 中的事件循环(event loop),以及微任务 和宏任务的概念

    说事件循环(event loop)之前先要搞清楚几个问题. 1. js为什么是单线程的? 试想一下,如果js不是单线程的,同时有两个方法作用dom,一个删除,一个修改,那么这时候浏览器该听谁的? 2. ...

  8. javascript事件循环Event Loop,宏任务与微任务

    1.javascript的运行机制介绍 javascript是单线程的语言,默认情况下一个时间点只能做一件事情,因此引入异步模型javascript是一门解释性脚本语言,即(边解释边运行) 2.阻塞式 ...

  9. [转] JavaScript:彻底理解同步、异步和事件循环(Event Loop)

    一. 单线程 我们常说"JavaScript是单线程的". 所谓单线程,是指在JS引擎中负责解释和执行JavaScript代码的线程只有一个.不妨叫它主线程. 但是实际上还存在其他 ...

最新文章

  1. LeetCode中等题之区域和检索 - 数组可修改
  2. 多传感器融合之滤波(一)——卡尔曼滤波(KF)推导
  3. 的训练过程_【能力模式】能力培养是一个训练过程,掌握三个要点,一个诀窍...
  4. vue 组件之间函数传递_组件之间相互传递参数
  5. mysql-connector-mysql 8.0 (spring-boot-starter-parent 管理的版本) + Activiti 6.x 自动建表失败
  6. matlab fwrite 多字节,单片机多字节串口接收
  7. ASP.NET Web API中实现版本的几种方式
  8. 页面校验请求MmEwMD(转载)
  9. 从模板引擎到模板引擎-使用aspx页面作为模板引擎的一种实现
  10. 【从零开始学GIS再到精通GIS】专题图制作-地图渲染-地图整饰
  11. HTC vive手柄在三维空间画线
  12. untiy对过相机参数计算视场角
  13. Java反编译工具Luyten
  14. win2003群集cluster下SQL2005和sp3补丁安装配置3
  15. win10计算机共享在哪,快速共享电脑文件,win10的“就近共享”功能了解一下!...
  16. SEO快速排名是什么,百度快速排名软件还有用吗?
  17. 计算机在汉语言文学专业中的应用,浅谈信息技术在中专学校汉语言文学专业中的应用...
  18. 苹果手机账号验证失败连接不上服务器,Apple ID登录连接服务器验证失败怎么解决?...
  19. 虚拟服务器无法获取ip地址,VMware下网络模式配置与IP地址无法正常获取及解决方案...
  20. 基于STM32F0实现人体红外传感器

热门文章

  1. BZOJ.2707.[SDOI2012]走迷宫(期望 Tarjan 高斯消元)
  2. 树莓派学习——音频视频播放
  3. mysql DbProviderFactories.GetFactory失败,解决方法
  4. Porter Stemming Algorithm
  5. android 去锯齿
  6. Silverlight三维透视+倒影效果
  7. oracle导入java包时出错,Oracle导入导出的常见错误
  8. mysql集群不同步_mysql数据库集群出现1236错误导致主库与从库无法同步的
  9. unity 异步加载网络图片_一个非常好用的AssetBundle资源加载器
  10. VS2015配置opencv教程(图文详解)