目录

  • 前言
    • 1、JS 的 执行引擎 与 执行环境
    • 2、js 是单线程的
  • 一、事件循环(Event Loop)
  • 二、任务队列
  • 三、宏任务 与 微任务
    • 1、宏任务
    • 2、微任务
    • 3、宏任务与微任务的运行机制
  • 四、Event Loop 实例
    • 1、案例一
    • 2、案例二
    • 3、案例三

前言

1、JS 的 执行引擎 与 执行环境

简单来说,为了让 JavaScript 运行起来,要完成两部分工作(当然实际比这复杂的多):

  • Engine(执行引擎):编译并执行 JavaScript 代码,完成内存分配、垃圾回收等。
  • Runtime(执行环境):为 JavaScript 提供一些对象或机制,使它能够与外界交互。

在 JavaScript 运行的时候,JavaScript Engine 会创建和维护相应的堆(Heap)和栈(Stack),同时通过 JavaScript Runtime 提供的一系列 API(例如:setTimeout、XMLHttpRequest 等)来完成各种各样的任务。

2、js 是单线程的

进程:
- 资源分配的最小单位。
- 指在系统中正在运行的一个应用程序。
- 程序一旦运行就是进程。

线程:
- 程序执行的最小单位。
- 系统分配处理器时间资源的基本单元,或者说进程之内独立执行的一个单元执行流。

JavaScript 是一种单线程的编程语言,只有一个调用栈,决定了它在同一时间只能做一件事情。

在 JavaScript 的运行过程中,真正负责执行 JavaScript 代码的始终只有一个线程,通常被称为主线程,各种任务都会用排队的方式来同步执行。

然而 JavaScript 却又是一个非阻塞(Non-blocking)、异步(Asynchronous)、并发式(Concurrent)的编程语言,这就得说说 JavaScript 的事件循环(Event Loop)机制了。

一、事件循环(Event Loop)

事件循环(Event Loop) 是让 JavaScript 做到既是单线程,又绝对不会阻塞的核心机制,也是 JavaScript 并发模型(Concurrency Model)的基础,是用来协调各种事件、用户交互、脚本执行、UI 渲染、网络请求等的一种机制。简而言之——Event Loop 是 JS 实现异步的一种机制

Event Loop 包含 2 种:一种存在于 Browsing Context 中,还有一种在 Worker 中。

二者的运行是独立的。也就是说,每一个 JavaScript 运行的“线程环境”都有一个独立的 Event Loop,每一个 Web Worker 也有一个独立的 Event Loop。

二、任务队列

Event Loop(事件循环)是通过 任务队列 的机制来进行协调的。

任务队列 的特点:

  • 一个 事件循环 中可以有一个或者多个 任务队列,一个 任务队列 便是一系列有序 任务 的集合。
  • 每个 任务 都有一个 任务源,同一个 任务源 的 任务 必须放到同一个 任务队列 中。
  • setTimeout、Promise 等 API 便是 任务源,而进入 任务队列 的是他们指定的具体执行任务。

在事件循环中,每进行一次循环操作称为 tick,每一次 tick 的任务处理模型是比较复杂的,但关键步骤如下:

  • 在此次 tick 中选择最先进入队列的任务(oldest task),如果有则执行(一次);
  • 检查是否存在 Microtasks,如果存在则不停地执行,直至清空 Microtasks Queue;
  • 更新 render;
  • 主线程重复执行上述步骤。

在上述 tick 的基础上需要了解几点:

  • JS 分为同步任务和异步任务;
  • 同步任务都在主线程上执行,形成一个执行栈;
  • 主线程之外,事件触发线程管理着一个任务队列,只要异步任务有了运行结果,就在任务队列之中放置一个事件;
  • 一旦执行栈中的所有同步任务执行完毕(此时 JS 引擎空闲),系统就会读取任务队列,将可运行的异步任务添加到可执行栈中,开始执行。

三、宏任务 与 微任务

1、宏任务

(macro)task,可以理解是每次执行栈执行的代码就是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行)。

浏览器为了能够使得JS内部(macro)task与DOM任务能够有序的执行,会在一个(macro)task执行结束后,在下一个(macro)task 执行开始前,对页面进行重新渲染——(macro)task->渲染->(macro)task->...

宏任务包含:script(整体代码)、setTimeout、setInterval、I/O、UI交互事件、postMessage、MessageChannel 和 setImmediate(Node.js 环境)。

2、微任务

microtask 可以理解是在当前 task 执行结束后立即执行的任务。也就是说,在当前task任务后,下一个task之前,在渲染之前。

所以它的响应速度相比setTimeout(setTimeout 是 task)会更快,因为无需等渲染。也就是说,在某一个 macrotask 执行完后,就会将在它执行期间产生的所有microtask都执行完毕(在渲染前)。

微任务包含:Promise、async/await、Object.observe、MutationObserver 和 process.nextTick(Node.js 环境)。

3、宏任务与微任务的运行机制

在事件循环中,每进行一次循环操作称为 tick,每一次 tick 的任务处理模型是比较复杂的,但关键步骤如下:

  • 执行一个宏任务(栈中没有就从事件队列中获取)
  • 执行过程中如果遇到微任务,就将它添加到微任务的任务队列中
  • 宏任务执行完毕后,立即执行当前微任务队列中的所有微任务(依次执行)
  • 当前宏任务执行完毕,开始检查渲染,然后 GUI 线程接管渲染
  • 渲染完毕后,JS 线程继续接管,开始下一个宏任务(从事件队列中获取)

四、Event Loop 实例

1、案例一

console.log(1);setTimeout(() => {console.log(2);Promise.resolve().then(() => {console.log(3)});
});new Promise((resolve, reject) => {console.log(4)resolve(5)
}).then((data) => {console.log(data);
})setTimeout(() => {console.log(6);
})console.log(7);// 输出结果:1 4 7 5 2 3 6

解析:
首先需要知道的知识点包括:

  • js 是从上往下执行的。
  • promise 的两个作为参数的回调函数里的内容(除了 resolve(); 和 reject(); 函数外),也是与全局同步执行的
  • 执行顺序:同步代码 > 微任务代码 > 宏任务代码。async/await 函数会有点特殊

执行步骤:

  • 首先会执行同步的代码,输出:1,4,7。
  • 执行微任务,此时的微队列中的任务为 Promise 中的 resolve(5) 则输出:5。
  • 执行宏队列中的队首任务(注意只执行一个宏任务),此时的队首任务为代码中第一个setTimeOut,则输出了:2。在执行这个任务时又产生了一个新的微任务。
  • 执行新产生的微任务,所以输出了:3。
  • 然后宏队列中还有一个任务,于是输出:6。

2、案例二

function fn2 () {console.log(1);return new Promise(resolve => {resolve(2);console.log(3);})
}
console.log(4);
fn2().then(res => console.log(res));
console.log(5);// 输出结果:4 1 3 5 2

解析:

  • js 是从上往下执行的,首先会执行同步的代码:4。
  • 然后执行函数 fn2():1。
  • 然后执行函数里 promise 对象里的同步代码:3,而 resolve() 里的内容会在微任务里稍后执行。
  • 走完 fn2() 函数的同步逻辑后,会执行同步的代码: 5。
  • 然后才是 fn2() 函数里的微任务代码(异步):2。

3、案例三

async function fn1 () {console.log(1);await new Promise(resolve => {resolve(2);console.log(3);})console.log(4);return 5;
}console.log(6);
fn1().then(res => console.log(res));// 不会打印 2,而是会打印 5
console.log(7);// 输出结果:6 1 3 7 4 5

解析:
首先需要知道的知识点包括:

  • async 函数总是会返回一个 promise 对象。
  • async 函数中,await 会中断同步代码的执行,需等到 await 代码执行完后才会继续执行同步代码。(执行顺序:async 函数外的同步代码 > async 函数里的同步代码。)

执行过程如下:

  • 首先会执行同步的输出:6。
  • 然后会执行函数 fn1() 里在 await 之前的同步的代码:1。
  • 然后会执行 await 标记的 promise 对象里的同步代码:3。而 resolve() 里的内容会在微任务里稍后执行。等待被 await 标记的代码(包括微任务和宏任务)执行完之后才会执行其后的代码。
  • 然后会继续执行 async 函数之外的同步的代码:7。
  • 然后会执行 async 函数里的 await 标记之后的同步的代码:4。
  • 然后,一般会在 then() 的回调函数里执行 resolve() 里传入的内容,可是接下来执行的 return 语句会覆盖掉 resolve() 传入的内容,作为 then() 回调函数的入参,所以之后会打印:5,而不是 2,因为 2 被 5 覆盖了。

【参考文章】
深入理解 JavaScript Event Loop-阿里 CCO 体验技术专刊首发
js中的宏任务与微任务
JavaScript 运行机制详解:再谈Event Loop

js 中的 Event Loop 以及 宏任务 与 微任务相关推荐

  1. 理解node.js中的 Event Loop

    node中的 "event loop" 正是node能处理高并发的核心所在.也正是因为它,node虽然在本质上是个单线程,却能让大量的操作处于后台运行.这篇文章将详细说明 even ...

  2. 为什么JS是单线程?JS中的Event Loop(事件循环)?JS如何实现异步?setimeout?

    https://segmentfault.com/a/1190000012806637 https://www.jianshu.com/p/93d756db8c81 首先,请牢记2点: (1) JS是 ...

  3. node.js中对Event Loop事件循环的理解

    javascript是单线程的,所以任务的执行都需要排队,任务分为两种,一种是同步任务,一种是异步任务. 同步任务是进入主线程上排队执行的任务,上一个任务执行完了,下一个任务才会执行. 异步任务是不进 ...

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

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

  5. js中的事件循环和宏任务和微任务的理解

    参考许多大神的文章,写下自己的理解 事件循环: 说到事件循环就得谈到js中同步和异步的执行顺序 1.javascript将任务分为同步任务和异步任务,同步任务放到主线中,异步函数首先进行回调函数注册. ...

  6. [译]理解js中的event loop

    之前看的文,感觉不太完整,于是找了篇详细的文章原文链接.翻译不正确的请指出,重在分享,如果有所收获就更好了. Javascript是如何异步和单线程的?简短的回答是javascript语言是单线程的, ...

  7. 详解队列在前端的应用,深剖JS中的事件循环Eventloop,再了解微任务和宏任务

    队列在前端中的应用 一.队列是什么 二.应用场景 三.前端与队列:事件循环与任务队列 1.event loop 2.JS如何执行 3.event loop过程 4. DOM 事件和 event loo ...

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

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

  9. 正确理解javascript中的Event loop机制

    这两个星期一直在想着写一篇关于javascript中event Loop的文章.自从写完上一篇<Javascript捕捉(capturing)与冒泡(bubbling)的区别>之后,我抛出 ...

最新文章

  1. 我为什么用ES做Redis监控,不用Prometheus或Zabbix?
  2. php 反序列化漏洞简介
  3. Codeforces 38B - Chess
  4. 让zabbix图像中文不再是乱码
  5. 仿码支付全新免签支付系统源码
  6. C语言之字符串探究(一):字符串与字符数组
  7. LeafGAN:一种有效的实用植物病害诊断数据扩充方法
  8. android 教程 百度云盘,【从零教程】带你从零编写自己的在线百度云盘 11-21更新...
  9. JSP(Java Server Pages)Java服务器页面
  10. 直播场景音频降噪,传统算法 VS AI 算法对比和实践
  11. android批量转换图片格式,批量图片格式转换器
  12. linux 关闭系统自动更新,Linux下如何关闭自动更新
  13. 政策 | 辅导班的“超纲教学”凉了?教育部印发六科负面清单!
  14. adb基础命令学习随笔
  15. scalac: Token not found...
  16. 大数据云计算技术概述_云计算–概述,类型,优势和未来范围
  17. GetAsyncKeyState用法
  18. e成科技人岗匹配中的匹配模型
  19. VR全景--720全景 助力行业数字化新模式
  20. 小米手机 adbinterface_啥?消息称小米正在研发1.5亿像素镜头手机

热门文章

  1. 2022-2027年中国纪录片行业市场全景评估及发展战略规划报告
  2. 字节跳动发布企业社会责任报告:92%双一流高校入驻抖音,总课时超145万小时
  3. java英文不好可以学吗_英语不好可以学好Java吗?
  4. 计算机网络实训课报告书,计算机网络实训报告
  5. 360lib投影格式介绍(二) - 立方体贴图投影(CMP / ACP / EAC / SSP / TSP)
  6. 【全面掌握windowXP系统优化的四个步骤 】
  7. 2022年出生的虎宝宝起名字大全 尊贵大气取名
  8. JAVA中阳历与阴历时间转换
  9. Google和facebook登录
  10. 案例分析|名创优品是如何通过精细化管理获得火速扩张的?