"精解 JavaScript 中的 Event Loop:微任务、宏任务全掌握"

前言

JavaScript 是一门单线程语言,这意味着它一次只能执行一个任务。这是因为 JavaScript 在设计之初就是作为浏览器脚本语言而诞生的,它的主要用途是与用户交互、操作 DOM 等。如果 JavaScript 是多线程的话,那么可能会导致对共享数据的操作变得复杂,容易出现竞争条件(race condition)等问题。JS中出现了同步和异步。那么接下来介绍一下同步和异步。

同步(Synchronous)执行: 在同步执行中,代码会按照顺序一行一行地执行,每行代码都必须等待上一行代码执行完成后才能继续执行。这意味着如果某个操作需要花费很长时间,那么整个程序的执行会被阻塞,直到该操作完成。

javascript 复制代码
console.log('开始');
// 执行一个耗时的操作
for (let i = 0; i < 1000000000; i++) {
 // 做一些耗时的计算
}
console.log('结束');

上面的例子中,当执行耗时的操作时,JavaScript 引擎会一直忙于计算,直到计算完成后才会继续执行下一行代码。

异步(Asynchronous)执行 : 在异步执行中,代码不会等待某个操作完成才继续执行,而是先将这个操作交给其他部件处理,自己继续执行其他代码。当操作完成后,通过回调函数或者 Promise 等机制来通知执行结果。

javascript 复制代码
console.log('开始'); // 执行一个异步操作 
setTimeout(function()
{ console.log('异步操作完成'); }, 1000);
console.log('结束');

进程与线程

进程(Process):

  • 一个进程代表着系统中运行的一个程序实例,它拥有独立的内存空间、文件描述符、以及其他系统资源。
  • 每个进程都是相互独立的,它们之间不能直接共享内存数据,而需要通过进程间通信的方式来进行数据交换。

线程(Thread):

  • 线程是进程中的一个实体,它可以被系统调度并执行。一个进程中可以包含多个线程,这些线程共享同一进程的内存空间和系统资源。
  • 在浏览器中,JavaScript 代码是运行在一个单独的线程中,这个线程被称为"JavaScript 引擎线程"。JavaScript 引擎线程负责执行 JavaScript 代码,并且处理与 DOM、CSSOM 相关的操作。

除了 JavaScript 引擎线程之外,浏览器还有其他一些线程,包括:

  1. GUI 渲染线程:负责渲染页面,处理与页面 UI 相关的操作。
  2. 事件触发线程:负责管理用户交互事件,比如鼠标点击、键盘输入等。
  3. 定时触发线程:负责处理定时器,以及一些与时间相关的操作。
  4. 异步 HTTP 请求线程:负责处理异步请求(如 Ajax 请求)的回调函数。

JS是单线程的优点

优点:

  1. 节约内存

  2. 没有锁的概念,节约上下文切换的时间

Event Loop

事件循环(Event Loop)是一种用于处理和调度异步操作的机制。它是在单线程环境下实现并发的关键组件。在一个应用程序中,可能存在多个异步任务,例如网络请求、文件读写操作等。这些任务不能立即完成,而是需要一定的时间。传统的编程模型中,我们会使用回调函数或者线程来处理这些异步任务,但是这样容易导致代码复杂、难以维护。

事件循环通过将所有的异步任务添加到一个任务队列中,并按照顺序依次执行这些任务,从而实现了异步操作的调度。它采用了事件驱动的方式,当某个任务完成时,会触发相应的回调函数。事件循环不断地从任务队列中取出任务执行,直到所有任务都完成。

微任务(microtask)和宏任务(macrotask)是指事件循环中的两种不同类型的任务。

  • 宏任务 (macrotask):script(整体代码)、setTimeout、setInterval、setImmediate'I/O、UI-rendering交互事件
  • 微任务 (microtask):Promise.then、MutationObserver,process.nextTick()

# 事件循环Event Loop执行机制

  1. 执行同步代码(这个属于宏任务)
  2. 当执行栈为空时,查询是否有异步需要执行
  3. 执行微任务
  4. 如果有需要,会渲染页面
  5. 执行宏任务( 下一次event-loop)

我来测试一下## Event Loop执行机制

javascript 复制代码
console.log(1);//1

setTimeout(() => {
    console.log(2);
    new Promise((resolve) => {
        console.log(4);
        resolve()
        setTimeout(() => {
            console.log(6);
        })
    }).then(() => {
        console.log(5);
    })
}, 1000)

console.log(3);

第一步执行同步代码,打印1,setTimeout是宏任务,要放进宏任务栈里面去,在打印3 第二部没有微任务,在开始一个循环执行打印2 在打印4 在打印 5 在打印6

注意选项

await

javascript 复制代码
console.log('stard');
async function async1() {
    await async2()//浏览器给await开小灶啦
    console.log('saync1 end');// 被await挤入微任务
}
async function async2() {
    console.log('saync2 end');
}
async1()

await右边的表达式会立即执行,浏览器给await开小灶啦,表达式之后 被await挤入微任务, await微任务可以转换成等价的promise微任务分析

执行同步代码(这个属于宏任务)

xml 复制代码
<script>
  console.log('script start');
  setTimeout(function () {
      console.log('setTimeout')
  }, 1000);
  console.log('script ');
</script>
<script>
  console.log('script end');
 
</script>

打印的结果为 'script start' ** 'script '** 'script end' 'setTimeout' 看到这里 大家应该把事件循环学的差不多啦吧 我来出一道题给大家试一下

大家把答案写在评论区吧 喜欢的来个关注 点赞 这个也是以后写文章的动力所在 谢谢大家能观看我的文章 咱下期再见 拜拜

相关推荐
耶啵奶膘23 分钟前
uniapp-是否删除
linux·前端·uni-app
王哈哈^_^2 小时前
【数据集】【YOLO】【目标检测】交通事故识别数据集 8939 张,YOLO道路事故目标检测实战训练教程!
前端·人工智能·深度学习·yolo·目标检测·计算机视觉·pyqt
cs_dn_Jie2 小时前
钉钉 H5 微应用 手机端调试
前端·javascript·vue.js·vue·钉钉
开心工作室_kaic3 小时前
ssm068海鲜自助餐厅系统+vue(论文+源码)_kaic
前端·javascript·vue.js
有梦想的刺儿3 小时前
webWorker基本用法
前端·javascript·vue.js
cy玩具4 小时前
点击评论详情,跳到评论页面,携带对象参数写法:
前端
清灵xmf4 小时前
TypeScript 类型进阶指南
javascript·typescript·泛型·t·infer
小白学大数据4 小时前
JavaScript重定向对网络爬虫的影响及处理
开发语言·javascript·数据库·爬虫
qq_390161774 小时前
防抖函数--应用场景及示例
前端·javascript
334554325 小时前
element动态表头合并表格
开发语言·javascript·ecmascript