js中的事件循环机制(宏任务和微任务)

JavaScript的事件循环机制是其非阻塞I/O模型的核心,它使得JavaScript能够在单线程环境中高效地处理异步操作。事件循环机制主要由以下几个部分组成:

  1. 调用栈(Call Stack)

    • 这是JavaScript执行同步代码的地方,后进先出(LIFO)的数据结构。
    • 当一个函数执行时,它会被推入栈顶,执行完毕后从栈顶弹出。
  2. 事件队列(Event Queue)

    • 也称为任务队列,用于存放异步操作的回调函数。
    • 事件队列可以有多个,但最常见的是宏任务队列和微任务队列。
  3. 宏任务(Macrotasks)

    • 包括如setTimeoutsetInterval、I/O操作、网络请求、UI渲染等
    • 每个宏任务执行完毕后,会检查并执行所有微任务队列中的微任务
  4. 微任务(Microtasks)

    • 包括Promise.then().catch().finally(),以及MutationObserver。(注意区分:new Promise,Promise构造函数是同步执行的)
    • 微任务的优先级高于宏任务,当调用栈清空后,会立即执行所有微任务队列中的微任务。
  5. 事件循环(Event Loop)

    • 事件循环是JavaScript运行时的调度机制,它不断地检查调用栈和事件队列。
    • 当调用栈清空时,事件循环会从宏任务队列中取出第一个任务执行,然后执行所有微任务队列中的微任务,接着检查是否需要进行UI渲染,然后再次检查宏任务队列。

事件循环的工作流程:

  1. 执行同步代码:同步代码在调用栈中执行,直到调用栈清空。
  2. 执行宏任务:调用栈清空后,事件循环从宏任务队列中取出第一个任务执行,将其推入调用栈。
  3. 执行微任务:宏任务执行完毕后,事件循环会立即执行所有微任务队列中的微任务,直到微任务队列清空。
  4. UI渲染:如果需要,浏览器会进行UI渲染更新。
  5. 重复循环下一个宏任务:如果宏任务队列中还有任务,事件循环会再次开始,执行下一个宏任务,直到调用栈和事件队列都为空。
console.log('Script start');setTimeout(function() {console.log('setTimeout');
}, 0);Promise.resolve().then(function() {console.log('promise1');
}).then(function() {console.log('promise2');
});console.log('Script end');

 

执行顺序如下:

  1. 执行同步代码 console.log('Script start')
  2. 执行同步代码 setTimeout(function() { console.log('setTimeout'); }, 0);。这个宏任务被添加到宏任务队列。
  3. 执行同步代码 Promise.resolve().then(function() { console.log('promise1'); }).then(function() { console.log('promise2'); });。这两个微任务被添加到微任务队列。
  4. 执行同步代码 console.log('Script end')
  5. 同步代码执行完毕,开始执行微任务队列中的所有微任务。首先执行第一个微任务 console.log('promise1')
  6. 执行第二个微任务 console.log('promise2')
  7. 微任务队列清空,执行渲染更新(如果有的话)。
  8. 检查宏任务队列,执行 setTimeout 中的回调函数 console.log('setTimeout')

输出结果:

Script start

Script end

promise1

promise2

setTimeout 

这道题会做了,应该就彻底理解了:

setTimeout(() => {console.log('1');new Promise(function (resolve, reject) {console.log('2');setTimeout(() => {console.log('3');}, 0);resolve();}).then(function () {console.log('4')})}, 0);console.log('5'); setTimeout(() => {console.log('6');}, 0);new Promise(function (resolve, reject) {console.log('7');reject();resolve();}).then(function () {console.log('8')}).catch(function () {console.log('9')})console.log('10');

 输出结果:// 5 7 10 8 1 2 4 6 3

分析:

  1. setTimeout(() => { console.log('1'); ... }, 0); 被推入宏任务队列,因为 setTimeout 是一个宏任务。

  2. console.log('5'); 执行,输出 '5'。

  3. setTimeout(() => { console.log('6'); }, 0); 被推入宏任务队列。

  4. new Promise(...) 创建了一个 Promise 实例,其执行器函数立即执行(因为Promise构造函数是同步执行的),console.log('7'); 输出 '7'。

  5. resolve(); 在Promise的执行器函数中被调用,这将Promise状态变为resolved,并将 .then(function () { console.log('8') }) 中的回调函数推入微任务队列。

  6. console.log('10'); 执行,输出 '10'。

至此,主线程中的同步代码执行完毕,事件循环开始处理微任务队列:

  1. 微任务队列中的 .then(function () { console.log('8') }) 执行,输出 '8'。

  2. 由于没有其他的微任务,事件循环开始处理宏任务队列中的下一个宏任务:

    • 首先执行 setTimeout(() => { console.log('1'); ... }, 0); 中的回调:
      • console.log('1'); 输出 '1'。
      • new Promise(...) 创建并立即执行执行器函数中的代码:
        • console.log('2'); 输出 '2'。
        • 内部的 setTimeout(() => { console.log('3'); }, 0); 被推入宏任务队列。
        • resolve(); 被调用,.then(function () { console.log('4') }) 中的回调函数被推入微任务队列。
      • console.log('4') 由于 resolve() 调用后立即推入微任务队列,输出 '4'。
  3. 事件循环再次处理微任务队列,输出 '4'。

  4. 然后,事件循环处理宏任务队列中的下一个宏任务,执行 setTimeout(() => { console.log('6'); }, 0); 中的回调,输出 '6'。

  5. 由于宏任务队列中还有之前由 console.log('2'); 内部创建的 setTimeout(() => { console.log('3'); }, 0);,事件循环最终处理这个宏任务,输出 '3'。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/848497.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android状态栏适配问题

Android状态栏适配是一个老生常谈的问题,那么我又拿出来讲了,因为这个东西确实太重要了,基本上每个项目都用得到。状态栏总共有几种形态。第一,让状态栏颜色跟应用主色调一致,布局内容不占有状态栏的位置。第二&#x…

c++学习笔记“类和对象”;友元函数

目录 4.4 友元 4.4.1 全局函数做友元 4.4.1 类做友元 4.4.1 成员函数做友元 4.4 友元 生活中你的家有客厅(Public),有你的卧室(Private) 客厅所有来的客人都可以进去,但是你的卧室是私有的,也就是说只有你能进去但是呢,你也可…

PSOPT在Ubuntu22.04下的安装

求解器pospt的原链接如下: PSOPT/psopt: PSOPT Optimal Control Software (github.com) 在该文件夹下提供了安装的指导文件,文件内容如下: 在 Ubuntu 22.04 中,如果按照适用于 Ubuntu 20.04 的说明执行 PSOPT 代码,目…

详细分析Mysql中的SQL_MODE基本知识(附Demo讲解)

目录 前言1. 基本知识2. Demo讲解2.1 ONLY_FULL_GROUP_BY2.2 STRICT_TRANS_TABLES2.3 NO_ZERO_IN_DATE2.4 NO_ENGINE_SUBSTITUTION2.5 ANSI_QUOTES 前言 了解Mysql内部的机制有助于辅助开发以及形成整体的架构思维 对于基本的命令行以及优化推荐阅读: 数据库中增…

完美解决 mysql 报错ERROR 1524 (HY000): Plugin ‘mysql_native_password‘ is not loaded

文章目录 错误描述错误原因解决步骤 跟着我下面的步骤走,解决你的问题,如果解决不了 私信我来给你解决 错误描述 执行ALTER USER root% IDENTIFIED WITH mysql_native_password BY 123456;报错ERROR 1524 (HY000): Plugin mysql_native_password is not …

596. 超过5名学生的课

596. 超过5名学生的课 题目链接:596. 超过5名学生的课 代码如下: # Write your MySQL query statement below selectclass from (select class,count(student) as num from Courses group by class) as t where num > 5

AI炒股:获取个股的历史成交价格并画出K线图

任务:获取贵州茅台的近几个月的价格数据,绘制k线图; 在deepseek中输入提示词: 你是一个Python编程专家,要完成一个编写Python脚本的任务,具体步骤如下: 用AKShare库获取股票贵州茅台&#xf…

PID算法在电机速度控制上的应用

目录 概述 1 系统硬件框架 1.1 框架介绍 1.2 硬件实物图 2 STM32Cub生成工程 2.1 软件版本信息 2.2 配置参数 ​编辑2.3 生成项目 3 PID算法实现 3.1 概念 3.2 代码实现 4 其他功能实现 4.1 设置电机速度 4.2 PID算法控制电机 4.3 功能函数的调用 5 测试 5.1 …

Python怎么给图片加水印

在Python中,可以使用PIL(Python Imaging Library)库或者其更活跃的分支Pillow来给图片添加水印。下面是一个简单的示例,展示如何使用Pillow给图片添加文本水印: from PIL import Image, ImageDraw, ImageFont# 打开原…

3072. 将元素分配到两个数组中 II Rust 线段树 + 离散化

题目 给你一个下标从 1 开始、长度为 n 的整数数组 nums 。 现定义函数 greaterCount ,使得 greaterCount(arr, val) 返回数组 arr 中 严格大于 val 的元素数量。 你需要使用 n 次操作,将 nums 的所有元素分配到两个数组 arr1 和 arr2 中。在第一次操…

winscp无法上传,删除,修改文件并提示权限不够的分析

使用winscp删除文件,报了个错如下 根据这个错就去百度,网上大部分都是通过下面这种方法解决: 在winscp端进行设置 输入主机名(即IP地址)、用户名和密码,然后点击高级 在箭头所指位置输入sudo + sftp应用程序的路径 先查询 sudo find / -name sftp-server -print点击Sh…

如何让 AI 自动阅读文档样例,编写符合你需求的代码?

(注:本文为小报童精选文章。已订阅小报童或加入知识星球「玉树芝兰」用户请勿重复付费) 痛点 我本科读的计算机专业。当时编程,讲究的就是个扎实。例如哈夫曼编码用来压缩解压文件,那真的是自己一行行代码写过来的。更…

【Pytorch】计算机视觉项目——卷积神经网络TinyVGG模型图像分类(如何使用自定义数据集)

目录 一、前言二、工作流程回顾三、详细步骤流程1. 环境配置2. 数据准备数据集下载数据存储结构&路径查看图片 3. 数据转换4. 自定义数据集(Custom Dataset )4.1 方法一:使用ImageFolder加载数据集信息查看张量转图片创建DataLoader 4.2 …

大型ERP设计-业务与功能指引:委托加工二(有偿供料)

委托加工二(有偿提供材料) 前言:在对ORACLE和SAP的核心模块功能全面解读的基础上,给出大型ERP设计的建议-业务与功能指引,企业选型、开发大型ERP软件的公司和ERP顾问可以参考。模块包括财务、计划与制造、供应链、项目…

Android AAudio——C API创建AudioTrack(六)

虽然 AAudio 试图提供一种直接的硬件访问途径,但在某些场景下,如处理兼容性问题、使用系统服务(如 AudioFlinger)或者在某些设备上,使用 AudioTrack 可能是最有效或最合适的途径。这并不违背 AAudio 的初衷,因为它的目标是提供高性能的音频处理,而不是避免使用系统服务。…

Java Web学习笔记12——JavaScript字符串

String&#xff1a; String字符串对象创建方法有两种&#xff1a; 方式一&#xff1a; var str new String("Hello String"); 方式二&#xff1a; var str "Hello String"; 常见的属性和方法&#xff1a; <!DOCTYPE html> <html lang"…

SwiftUI中ContentUnavailableView的使用(iOS 17、tvOS 17推出的新组件)

iOS 17为SwiftUI带来了一个新的组件ContentUnavailableView&#xff0c;它允许我们向用户呈现一个空状态&#xff0c;而不需要创建自定义错误或者无内容视图。 ContentUnavailableView易于使用&#xff0c;可自定义&#xff0c;并且具有用于空搜索状态的预定义视图。 建议在无…

【考研数学】基础到强化如何衔接? 强化阶段该怎么用书?

我的个人经验在强化阶段之前&#xff0c;只需要基本题型都掌握就足够了。 就比如1800基础篇的习题&#xff0c;你盖住答案自己能做对八九成&#xff0c;那就进入强化绝对够够的了。&#x1f609; 强化的时候&#xff0c;你的正确率可能骤降到三四成&#xff0c;但是完全不用慌!…

【C语言】详解函数(下)(庖丁解牛版)

文章目录 1. 前言2. 数组做函数形参3. 函数嵌套调用和链式访问3.1 嵌套调用3.2 链式访问 1. 前言 详解C语言函数(上)的链接&#xff1a;http://t.csdnimg.cn/EGsfe 经过对函数的初步了解之后,相信大家已经对C语言标准库里的函数已经有初步的认知了&#xff0c;并且还学会了如…

C++面试经验分享

C面经 文章目录 C面经智能指针**内存泄露与智能指针****智能指针有什么类型&#xff0c;各自的原理有什么区别 / 解释下智能指针的实现原理****shared_ptr怎么实现多指针指向同一个地址****引用计数如何保证不同类实例的指针之间共享同步****循环引用会在什么情况下产生&#x…