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

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

相关推荐
passerby60617 分钟前
如何自己造一个时间处理库
前端·javascript·github
走到天涯海角1 小时前
react里面的长列表渲染优化
前端·react.js·前端框架
小羊没烦恼!1 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
北岛贰2 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
Interview Aid1122 小时前
Walmart Global Tech SDE 三轮面经|基础、并发、压力面
面试·职场和发展
mayaairi3 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js
kyriewen4 小时前
面试官问我:AI 都能写代码了,前端凭什么还值 25K
前端·javascript·人工智能
风骏时光牛马4 小时前
AI源码分析:拆解模型底层实现逻辑
前端
BillKu5 小时前
全局样式变量:CSS 自定义属性(--border-color)和SCSS 变量($border-color)的说明
javascript·css·scss
IT_陈寒5 小时前
React子组件莫名其妙重渲染?你可能漏了这个Hook
前端·人工智能·后端