{{format('0')}} {{format('114')}} {{format('3544')}}

【前端】探索JavaScript事件循环机制 [ 前端 ]

晚安月亮 文章 正文

挣钱给咖喱买最好吃的罐罐
分享

椰奶冻

{{nature("2024-09-27 15:03:22")}}更新

1. 什么是事件循环机制?

JS 中的事件循环(Event Loop)是一种用于管理和调度异步任务执行的机制。它使得 JS 可以处理异步操作,如定时器、事件处理、网络请求等,而不会阻塞主线程的执行。

2. 说一下什么是宏任务微任务,为什么要定义这两种任务类型?

宏任务(macro tasks)和微任务(micro tasks)是 JavaScript 引擎中用于管理异步任务执行顺序的两种任务类型。

宏任务(Macro tasks): 是指那些需要在主线程中执行的任务,它们包括但不限于:

  • 定时器任务(Timers):通过 setTimeout、setInterval 创建的任务。
  • I/O 操作任务(I/O operations):例如文件读写、网络请求等异步操作。
  • 渲染事件(UI Rendering):处理用户交互事件(例如鼠标点击、键盘事件等)的任务。
  • 事件处理器任务(Event handlers):事件监听器、事件回调等。

微任务(Micro tasks): 是指在当前任务执行完成后立即执行的任务,它们通常包括:

  • Promise 回调(Promise callbacks):使用 Promise 对象的 then 方法添加的回调函数。
  • MutationObserver 回调:通过 MutationObserver 观察 DOM 变化并触发的任务。
  • process.nextTick(在 Node.js 环境中):在事件循环的当前回合结束时执行的任务。

宏任务和微任务的引入使得 JavaScript 引擎能够更好地处理异步任务。

宏任务用于表示一组相对较大的任务单元,而微任务用于表示一组相对较小、优先级较高的任务单元。

通过微任务,我们可以在宏任务执行完成后立即执行一些重要的任务,如更新 UI、处理 Promise 的回调等,以提高应用的响应速度和用户体验。

3. 例题:

1.

  async function async1() {
    console.log('async1 start');
    await async2();
    console.log('async1 end');
  }
  async function async2() {
    console.log('async2');
  }
  console.log('script start');
  setTimeout(function () {
    console.log('setTimeout');
  }, 0);
  async1();
  new Promise(function (resolve) {
    console.log('promise1');
    resolve();
  }).then(function () {
    console.log('promise2');
  });
  console.log('script end');

答案:
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout

过程:

1. 同步任务(同步代码执行)

首先,所有同步任务按顺序执行。

  • 第 1 步console.log('script start');
    • 输出:script start
  • 第 2 步:调用 async1 函数。
    • 进入 async1 函数,console.log('async1 start');
    • 输出:async1 start
    • 遇到 await async2()async2 被调用。
  • 第 3 步:进入 async2 函数,console.log('async2');
    • 输出:async2
    • async2 函数执行结束,回到 async1
  • 第 4 步await 表达式遇到一个 Promiseasync1 函数暂停并将控制权交回主线程,继续执行后面的同步代码。
  • 第 5 步:创建一个 Promise,立即执行其回调函数,console.log('promise1');
    • 输出:promise1
  • 第 6 步Promise 的回调函数执行完毕,注册了一个 .then 回调到微任务队列。
  • 第 7 步console.log('script end');
    • 输出:script end

2. 微任务(Microtasks)队列处理

主线程上的同步任务执行完毕,开始处理微任务队列。

  • 第 8 步async1await 表达式完成(此时它已经变成一个 Promise),恢复执行 async1 函数的后续代码。
    • 执行 console.log('async1 end');
    • 输出:async1 end
  • 第 9 步Promise.then 回调执行。
    • 执行 console.log('promise2');
    • 输出:promise2

3. 宏任务(Macrotasks)队列处理

微任务队列清空后,开始处理宏任务队列中的任务。

  • 第 10 步 :处理

    setTimeout

    的回调函数。

    • 执行 console.log('setTimeout');
    • 输出:setTimeout

2.

const promise = new Promise((resolve, reject) => {
    console.log(1);
  setTimeout(() => {
    console.log("6");
    setTimeout(()=>{console.log(8);},0)
    resolve('success')
    console.log(7);
  }, 0);
  console.log(2);
});
setTimeout(()=>{
    console.log(5);
},0)

promise.then((res)=>{
    console.log(res);
})
console.log(4);

答案:
1
2
4
5
6
7
success
8

1. 执行宏任务(Macrotask

  • 遇到第一个宏任务(setTimeout 回调),执行回调函数:
    • 输出:5
  • 执行下一个宏任务(Promise 内的 setTimeout 回调),执行回调函数:
    • 输出:6
    • 注册一个新的 setTimeout,将其加入到宏任务队列中。
    • 调用 resolve('success'),将 then 回调加入到微任务队列中。
    • 输出:7

2. 执行微任务(Microtask

  • 执行微任务队列中的回调函数:

    • 执行
    promise.then

    的回调,输出

    res

    的值:

    success
    • 输出:success

3. 执行下一个宏任务(Macrotask

  • 执行最后一个

    setTimeout

    回调:

    • 输出:8
评论 0
0
{{userInfo.data?.nickname}}
{{userInfo.data?.email}}
TOP 2
【笔经】数字马力前端笔试-22应届

{{nature('2022-06-23 23:10:58')}} {{format('1477')}}人已阅读

TOP 3
【React】React组件卸载生命周期、路由跳转、页面关闭(刷新)拦截提示

{{nature('2023-02-03 16:12:08')}} {{format('1397')}}人已阅读

TOP 4
【前端】npm/yarn报错:getaddrinfo ENOTFOUND registry.nlark.com

{{nature('2024-05-29 15:14:38')}} {{format('1025')}}人已阅读

TOP 5
【前端】jspdf+dom-to-image生成多页A4pdf加防截断处理

{{nature('2024-05-24 15:20:21')}} {{format('905')}}人已阅读

目录

标签云

JavaScript

一言

# {{hitokoto.data.from || '来自'}} #
{{hitokoto.data.hitokoto || '内容'}}
作者:{{hitokoto.data.from_who || '作者'}}
自定义UI
配色方案

侧边栏