"精解 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' 看到这里 大家应该把事件循环学的差不多啦吧 我来出一道题给大家试一下

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

相关推荐
风抽过的烟头1 分钟前
Python提取字符串中的json,时间,特定字符
前端·python·json
SomeB1oody17 分钟前
【Rust自学】6.3. 控制流运算符-match
开发语言·前端·rust
m0_7482567844 分钟前
【Django自学】Django入门:如何使用django开发一个web项目(非常详细)
前端·django·sqlite
林小白的日常1 小时前
uniapp中wx.getFuzzyLocation报错如何解决
前端·javascript·uni-app
傻小胖1 小时前
React 脚手架配置代理完整指南
前端·react.js·前端框架
EterNity_TiMe_1 小时前
【论文复现】农作物病害分类(Web端实现)
前端·人工智能·python·机器学习·分类·数据挖掘
余生H2 小时前
深入理解HTML页面加载解析和渲染过程(一)
前端·html·渲染
吴敬悦2 小时前
领导:按规范提交代码conventionalcommit
前端·程序员·前端工程化
ganlanA2 小时前
uniapp+vue 前端防多次点击表单,防误触多次请求方法。
前端·vue.js·uni-app
卓大胖_2 小时前
Next.js 新手容易犯的错误 _ 性能优化与安全实践(6)
前端·javascript·安全