当前位置: 首页 > news >正文

一篇文章搞明白js运行机制——事件循环

1、解释 JavaScript 的执行机制。

        JavaScript 的执行机制基于事件循环。事件循环包括一个任务队列(Task Queue)和一个微任务队列(Microtask Queue)。当一个函数被调用时,它被添加到微任务队列中。事件循环每次迭代都会先执行微任务队列中的所有任务,然后执行一个宏任务(Macrotask),例如脚本代码、setTimeout、setInterval、setImmediate、I/O、UI 渲染等。当一个宏任务执行完成后,事件循环会再次检查微任务队列,并执行所有的微任务。这个过程会一直循环下去,因此被称为“事件循环”。

2、解释 JavaScript 中的事件循环。

        事件循环是 JavaScript 的核心运行机制,它负责调度和执行所有的任务。事件循环包括一个任务队列(Task Queue)和一个微任务队列(Microtask Queue)。当一个函数被调用时,它被添加到微任务队列中。事件循环每次迭代都会先执行微任务队列中的所有任务,然后执行一个宏任务(Macrotask),例如脚本代码、setTimeout、setInterval、setImmediate、I/O、UI 渲染等。当一个宏任务执行完成后,事件循环会再次检查微任务队列,并执行所有的微任务。这个过程会一直循环下去,因此被称为“事件循环”。

3、解释 JavaScript 中的任务队列和微任务队列。

        任务队列(Task Queue)和微任务队列(Microtask Queue)都是事件循环中的重要概念。任务队列用于存储宏任务(Macrotask),例如脚本代码、setTimeout、setInterval、setImmediate、I/O、UI 渲染等。当一个宏任务被添加到任务队列中时,它会在下一个事件循环中被执行。微任务队列用于存储微任务(Microtask),例如 Promise 的回调函数、process.nextTick 等。微任务会在当前事件循环的宏任务执行完成后立即执行,无论它们何时被添加到微任务队列中。

4、为什么 setTimeout(fn, 0) 的执行会发生在下一轮事件循环?

        setTimeout(fn, 0) 的执行会发生在下一轮事件循环,因为 setTimeout 将函数 fn 添加到任务队列中,而任务队列中的宏任务会在下一个事件循环中被执行。由于 setTimeout 的延迟参数为 0,所以 fn 会在下一个事件循环中被立即执行。

5、什么是宏任务和微任务?它们之间的区别是什么?

        宏任务(Macrotask)和微任务(Microtask)是事件循环中的两种不同类型的任务。
宏任务包括整个脚本代码、setTimeout、setInterval、setImmediate、I/O、UI 渲染等。
微任务包括 Promise 的回调函数、process.nextTick 等。
        它们之间的区别在于执行时机和执行顺序。每次事件循环迭代时,都会执行一个宏任务和所有的微任务,但是宏任务的执行会打断微任务的执行。因此,微任务的执行优先级高于宏任务。

6、解释一下 JavaScript 中的 Promise.then 和 Promise.catch 是如何工作的?它们和事件循环有什么关系?

        Promise.then 和 Promise.catch 是 JavaScript 中处理异步操作的重要函数。Promise 对象代表一个异步操作的最终完成(或失败)及其结果值。

Promise.then 方法返回一个新的 Promise 对象,称为 thenable。thenable 表示一个可以像 Promise 一样进行处理的类似 Promise 对象。当 Promise 完成时,thenable 的回调函数将被触发。

Promise.catch 方法返回一个 Promise,该 Promise 在第一个拒绝的 Promise 或 thenable 拒绝时触发。

Promise.then 和 Promise.catch 都与事件循环有关。在 JavaScript 的执行模型中,有一个任务队列(task-queue)和一个微任务队列(microtask-queue)。当一个异步事件(如定时器、Ajax 请求)完成后,它的回调函数会被添加到微任务队列中。在下一次循环中,JavaScript 会先处理微任务队列中的所有任务,然后再处理任务队列中的任务。Promise.then 和 Promise.catch 的回调函数会在微任务队列中等待执行。当 Promise 完成或被拒绝时,相应的回调函数会被添加到微任务队列中,并在下一次循环中执行。

7、解释一下 JavaScript 中的 MutationObserver 和它与事件循环的关系。

        MutationObserver 是一个提供监控 DOM 树更改的能力的接口。它被设计为在 DOM 树更改时提供低延迟的通知。MutationObserver 与事件循环的关系在于它的回调函数会在微任务队列中等待执行。当 DOM 树发生更改时,MutationObserver 的回调函数会被添加到微任务队列中,并在下一次循环中执行。

8、描述一下 JavaScript 中的 call stack 和 event loop。

        在 JavaScript 中,执行环境(Execution Context)是用于描述 JavaScript 代码运行的环境的概念。当 JavaScript 代码被执行时,会创建一个新的执行环境,并且该环境会一直存在直到代码执行完成。执行环境主要包括 call stack 和 heap。

call stack 是一个后入先出(LIFO)的数据结构,用于存储当前执行中的函数调用。当一个函数被调用时,它被添加到 call stack 的顶部。当函数执行完成时,它从 call stack 中移除。

event loop 是一个循环的过程,它会不断地检查 call stack 是否为空。如果 call stack 不为空,event loop 会从 call stack 中取出一个任务(可以是宏任务也可以是微任务)执行,然后将结果添加到微任务队列中。然后,event loop 会检查微任务队列是否为空。如果微任务队列不为空,event loop 会从微任务队列中取出所有的微任务并执行它们。然后,event loop 会再次检查 call stack 是否为空,并重复这个过程。

9、什么是 JavaScript 的事件循环?请简述其工作原理。

         事件循环是 JavaScript 的核心执行机制。它由一个或多个循环组成,每个循环称为一次循环或一次迭代。在每次循环中,事件循环会按照一定的顺序执行一系列的任务,包括处理用户交互、执行脚本代码、处理网络请求等。

事件循环的工作原理如下:

  1. 执行单次循环:事件循环开始执行单次循环。在单次循环中,事件循环会按照一定的顺序执行一系列的任务,包括处理用户交互、执行脚本代码、处理网络请求等。这些任务被称为宏任务(macro-tasks),包括 script(整体代码)、setTimeout、setInterval、setImmediate、I/O、UI rendering 等。在单次循环的末尾,事件循环会检查微任务队列(microtask-queue)。
  2. 处理微任务:如果微任务队列中有任务,事件循环会立即执行所有的微任务,直到微任务队列为空。微任务包括 Promise.then、process.nextTick、MutationObserver 等。在单次循环的末尾处理微任务是很重要的,因为它们通常与异步操作相关联,而这些操作需要在当前的同步操作之后立即执行。
  3. 检查终止条件:如果当前的单次循环已经执行了所有的宏任务和微任务,并且没有其他的同步操作需要执行,那么事件循环就会结束当前的单次循环并开始下一个单次循环。否则,事件循环会继续等待下一个宏任务到达并开始下一个单次循环。

10、事件循环中的 microtask 和 macrotask 有什么区别?

在 JavaScript 的事件循环中,任务被分为两种类型:microtask 和 macrotask。

Macrotask:Macrotask 是指那些需要较长时间才能完成的任务,例如 script(整体代码)、setTimeout、setInterval、setImmediate、I/O、UI rendering 等。

Microtask:Microtask 是一种 JavaScript 任务,它的执行优先级高于 macrotask。Microtask 包括但不限于 Promise 的回调函数、MutationObserver 的回调函数等。

事件循环中的 microtask 和 macrotask 的主要区别在于它们的执行优先级和执行时间。Macrotask 会等待同步代码执行完毕后,再在下一次事件循环中执行,而 microtask 会在同步代码执行完毕后立即执行,无论是否还有 macrotask 等待执行。因此,microtask 的执行优先级高于 macrotask。

11、JavaScript 中的 Promise 和 microtask 有何关系?

Promise 和 microtask 有密切的关系。当 Promise 的状态发生改变时(即从 pending 变为 resolved 或 rejected),会触发 microtask 队列的执行。这意味着,Promise 的回调函数(无论是 .then 还是 .catch)都会被添加到 microtask 队列中,并在下一次事件循环中执行。

因此,我们可以利用 Promise 和 microtask 的关系来确保在异步操作完成之后执行的代码能够立即执行,而不需要等待当前的同步代码执行完毕。例如,如果我们在一个 Promise 的回调函数中进行异步操作,那么这个异步操作也会被添加到 microtask 队列中,并在下一次事件循环中执行。因此,我们可以利用这个特性来确保在异步操作完成之后执行的代码能够立即执行,而不需要等待当前的同步代码执行完毕。


案例

1.微任务:Promise 回调函数,宏任务:setTimeout 回调函数

console.log('start');
setTimeout(() => console.log('setTimeout'), 0);
Promise.resolve().then(() => console.log('Promise'));
console.log('end');// start
// end
// Promise
// setTimeout

解析: 首先输出 start,然后通过 setTimeout 方法注册了一个回调函数,它会被添加到宏任务队列中。接着创建了一个 Promise 实例,并且通过 then 方法注册了一个回调函数,在 Promise 对象的状态改变时会执行这个回调函数。接着输出 end。因为 Promise 回调函数是微任务,所以它会被添加到微任务队列中,等待执行。等到主线程的同步任务执行完毕后,JavaScript 引擎会先执行微任务队列中的任务,输出 Promise,然后执行宏任务队列中的任务,输出 setTimeout

2.微任务:process.nextTick 回调函数,宏任务:setImmediate 回调函数

console.log('start');
setImmediate(() => console.log('setImmediate'));
process.nextTick(() => console.log('process.nextTick'));
console.log('end');// start
// end
// process.nextTick
// setImmediate

解析: 在 Node.js 环境中,process.nextTick 回调函数是排在微任务队列最前面的,优先级比 Promise 回调函数还要高。而 setImmediate 回调函数是排在宏任务队列最后面的。所以,以上代码会先输出 start,然后输出 end。等到主线程的同步任务执行完毕后,JavaScript 引擎会先执行微任务队列中的任务,输出 process.nextTick,然后执行宏任务队列中的任务,输出 setImmediate

3.微任务:Promise 回调函数,宏任务:requestAnimationFrame 回调函数

console.log('start');
requestAnimationFrame(() => console.log('requestAnimationFrame'));
Promise.resolve().then(() => console.log('Promise'));
console.log('end');// start
// end
// Promise
// requestAnimationFrame

解析: 首先输出 start,然后通过 requestAnimationFrame 方法注册了一个回调函数,它会被添加到宏任务队列中。接着创建了一个 Promise 实例,并且通过 then 方法注册了一个回调函数,在 Promise 对象的状态改变时会执行这个回调函数。接着输出 end。因为 Promise 回调函数是微任务,所以它会被添加到微任务队列中,等待执行。等到主线程的同步任务执行完毕后,JavaScript 引擎会先执行微任务队列中的任务,输出 Promise,然后执行宏任务队列中的任务,输出 requestAnimationFrame

4.微任务:Promise 回调函数,宏任务:XMLHttpRequest 回调函数

console.log('start');
const xhr = new XMLHttpRequest();
xhr.open('get','http://localhost:4000/get',true)
xhr.onload = () => console.log('XMLHttpRequest');
xhr.send();
Promise.resolve().then(() => console.log('Promise'));
console.log('end');//start
//end
//Promise
//XMLHttpRequest

解析: 首先输出 start,然后创建了一个 XMLHttpRequest 对象,并且通过 open 方法和 send 方法发送了一个 GET 请求。接着通过 onload 方法注册了一个回调函数,在请求成功后会执行这个回调函数。接着创建了一个 Promise 实例,并且通过 then 方法注册了一个回调函数,在 Promise 对象的状态改变时会执行这个回调函数。接着输出 end。因为 Promise 回调函数是微任务,所以它会被添加到微任务队列中,等待执行。等到主线程的同步任务执行完毕后,JavaScript 引擎会先执行微任务队列中的任务,输出 Promise,然后等待 XMLHttpRequest 对象的回调函数执行。当请求成功后,JavaScript 引擎会执行宏任务队列中的任务,输出 XMLHttpRequest

5.最终的案例:

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')
})
async1()
new Promise(function (resolve) {console.log('promise1')resolve()
}).then(function () {console.log('promise2')
})
console.log('script end')script start、async1 start 、saync2、promise1、script end、async1 end、promise2、settimeout

解析

1.执行整段代码,第一次执行同步任务:log(script start)

2.遇到定时器为异步任务先不执行

3.遇到async1()执行 打印async1 start 然后执行await 打印async2之后阻塞async1 end将其加入微任务列表 

4.跳出函数继续向下执行 碰到new promise执行 打印promise1 之后遇到.then为微任务加入为微物列表

5.跳出后执行最后一行代码 打印script end 至此第一轮宏任务执行完毕 开始执行微任务

6.此时微任务列表按顺序打印 async1 end、promise2微任务 至此微任务执行完毕

7.开启新一轮的事件循环 开始执行下一个宏任务 即定时器 打印settimeout

相关文章:

一篇文章搞明白js运行机制——事件循环

1、解释 JavaScript 的执行机制。 JavaScript 的执行机制基于事件循环。事件循环包括一个任务队列(Task Queue)和一个微任务队列(Microtask Queue)。当一个函数被调用时,它被添加到微任务队列中。事件循环每次迭代都会…...

Leetcode 第 371 场周赛题解

Leetcode 第 371 场周赛题解 Leetcode 第 371 场周赛题解题目1:100120. 找出强数对的最大异或值 I思路代码复杂度分析 题目2:100128. 高访问员工思路代码复杂度分析 题目3:100117. 最大化数组末位元素的最少操作次数思路代码复杂度分析 题目4…...

keras转onnx,TensorFlow转tf.keras.models.load_model,onnx精度转换

参考: https://blog.csdn.net/Deaohst/article/details/126864267 转onnx 别直接转onnx。 先转PB: import tensorflow as tfmodel_path ./models/model.h5 # 模型文件 model tf.keras.models.load_model(model_path) model.sa…...

高可用架构设计

1. 引言 软件系统有三个追求:高性能、高并发、高可用,俗称三高。三者既有区别也有联系,门门道道很多,本篇讨论高可用 高可用技术的重要性在于保证系统的连续可用性,提高系统的稳定性和可靠性。它可以应对高并发和大规…...

qemu 之 uboot、linux 启动

目录 编译uboot、kernel 编译启动从 uboot 中引导启动 linux注参考 本文主要说明 arm64 在 qemu 上的相关启动。 编译 使用的是 qemu-8.1.1 版本,编译命令如下: ../configure --cc/usr/local/bin/gcc --prefix/home/XXX/qemu_out --enable-virtfs --enable-slir…...

C语言--每日五道选择题--Day8

第一题 1、下列程序的输出是&#xff08; &#xff09; #include<stdio.h> int main() {int a[12] {1,2,3,4,5,6,7,8,9,10,11,12};int *p[4];int i;for(i0;i<4;i){p[i]&a[i*3];}printf("%d\n"&#xff0c;p[3][2]);return 0; } A: 上述程序有错误 B: 6…...

Outlook如何删除邮箱账户

Outlook如何删除邮箱账户 说明&#xff1a; 最近有用户询问到“我的Outlook登陆了很多个邮箱账号&#xff0c;不知道怎么退出”接下来将具体操作步骤加以说明 操作指引&#xff1a; 1、首先打开Outlook该软件&#xff0c;然后点击“文件” 2、点击账户设置下拉菜单 3、在下拉…...

ultrascale+mpsoc系列的ZYNQ中DDR4参数设置说明

ultrascalempsoc系列的ZYNQ中DDR4参数设置说明 标题1 概述标题2 讲述平台标题3 ZYNQ的DDR设置界面参数标题4 DDR参数界面说明如下 标题1 概述 本文用于讲诉ultrascalempsoc系列中的ZYNQ的DDR4的参数设置与实际硬件中的DDR选型之间的关系&#xff0c;为FPGA设计人员探明道路。 …...

maven-六类属性

Maven的六类属性_maven内置属性-CSDN博客 系统变量指的是java系统的变量&#xff0c;环境变量指的系统变量和用户变量 java系统仅针对java程序&#xff0c;环境变量是全局的。两者都可以传进java进程。 参考 01.java环境变量&#xff08;env&#xff09;和系统属性&#xf…...

微服务概念

微服务 微服务是什么 In short, the microservice architectural style [1] is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource A…...

响应式摄影科技传媒网站模板源码带后台

模板信息&#xff1a; 模板编号&#xff1a;540 模板编码&#xff1a;UTF8 模板颜色&#xff1a;黑白 模板分类&#xff1a;摄像、婚庆、家政、保洁 适合行业&#xff1a; 模板介绍&#xff1a; 本模板自带eyoucms内核&#xff0c;无需再下载eyou系统&#xff0c;原创设计、手…...

探索C#事件(Event)的强大应用

摘要 在现代软件开发中&#xff0c;对象之间的通信和交互是一个常见而重要的问题。为了解决这个问题&#xff0c;C#作为一种面向对象的编程语言提供了一种强大的特性&#xff1a;事件&#xff08;Event&#xff09;。事件可以帮助开发人员实现对象间的松耦合&#xff0c;提高代…...

学习c#的第四天

目录 C# 变量 C# 中的变量定义与初始化 接受来自用户的值 C# 中的 Lvalues 和 Rvalues 不同类型变量进行运算 静态变量 局部变量 C# 常量 整数常量 浮点常量 字符常量 字符串常量 定义常量 扩展知识 Convert.ToDouble 与 Double.Parse 的区别 静态常量和动态常…...

解析JSON字符串:属性值为null的时候不被序列化

如果希望属性值为null及不序列化&#xff0c;只序列化不为null的值。 1、测试代码 配置代码&#xff1a; mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); 或者通过注解JsonInclude(JsonInclude.Include.NON_NULL) //常见问题2&#xff1a;属性为null&a…...

短视频短剧小程序系统:用技术丰富你的碎片时间

在当今快节奏的生活中&#xff0c;人们的休闲时间变得越来越碎片化。短视频短剧小程序系统正是利用这一现象&#xff0c;通过技术手段为人们提供了丰富多样的娱乐内容&#xff0c;让碎片时间变得更加充实。 一、短视频短剧小程序系统的技术特点 高效加载与流畅播放&#xff1…...

服务器数据恢复—磁盘出现坏道掉线导致raid5阵列崩溃的数据恢复案例

服务器数据恢复环境&#xff1a; 某品牌服务器中有一组16块SAS接口硬盘组建的raid5磁盘阵列。 服务器故障&检测&#xff1a; 服务器raid5阵列中有2块硬盘掉线&#xff0c;上层服务器应用崩溃&#xff0c;导致服务器数据丢失。丢失的数据主要是4个1.5TB大小的卷中的数据&am…...

Android R.fraction

来源 我是在看Android10原生代码&#xff0c;绘制状态栏蓝牙电量相关类中第一次看到R.fraction的&#xff0c;如类BatteryMeterDrawable <fraction name"battery_button_height_fraction">10%</fraction> mButtonHeightFraction context.getResources(…...

C语言精华题目锦集1

第一题 test.c文件中包括如下语句&#xff0c;文件中定义的四个变量中&#xff0c;是指针类型的是&#xff08;&#xff09;【多选】 #define INT_PTR int* typedef int* intptr; INT_PRT a,b; int_ptr c,d;A:a  B:b  C:c  D:d #define是宏定义&#xff0c;此时在程序中IN…...

头歌答案Python——JSON基础

目录 ​编辑 Python——JSON基础 第1关&#xff1a;JSON篇&#xff1a;JSON基础知识 任务描述 第2关&#xff1a;JSON篇&#xff1a;使用json库 任务描述 Python——XPath基础 第1关&#xff1a;XPath 路径表达式 任务描述 第2关&#xff1a;XPath 轴定位 任务描述…...

TDengine 与煤科院五大系统实现兼容性互认,助力煤矿智能化安全体系搭建

近日&#xff0c;涛思数据与煤炭科学技术研究院&#xff08;以下简称煤科院&#xff09;已完成数个产品兼容互认证工作&#xff0c;经双方共同严格测试&#xff0c;涛思数据旗下物联网、工业大数据平台 TDengine V3.X 与煤炭科学技术研究院旗下煤矿复合灾害监测监控预警系统、煤…...

stm32G473的flash模式是单bank还是双bank?

今天突然有人stm32G473的flash模式是单bank还是双bank&#xff1f;由于时间太久&#xff0c;我真忘记了。搜搜发现&#xff0c;还真有人和我一样。见下面的链接&#xff1a;https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...

基于Flask实现的医疗保险欺诈识别监测模型

基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施&#xff0c;由雇主和个人按一定比例缴纳保险费&#xff0c;建立社会医疗保险基金&#xff0c;支付雇员医疗费用的一种医疗保险制度&#xff0c; 它是促进社会文明和进步的…...

聊聊 Pulsar:Producer 源码解析

一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台&#xff0c;以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中&#xff0c;Producer&#xff08;生产者&#xff09; 是连接客户端应用与消息队列的第一步。生产者…...

MODBUS TCP转CANopen 技术赋能高效协同作业

在现代工业自动化领域&#xff0c;MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步&#xff0c;这两种通讯协议也正在被逐步融合&#xff0c;形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

【单片机期末】单片机系统设计

主要内容&#xff1a;系统状态机&#xff0c;系统时基&#xff0c;系统需求分析&#xff0c;系统构建&#xff0c;系统状态流图 一、题目要求 二、绘制系统状态流图 题目&#xff1a;根据上述描述绘制系统状态流图&#xff0c;注明状态转移条件及方向。 三、利用定时器产生时…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)

🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

GitHub 趋势日报 (2025年06月08日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

MySQL中【正则表达式】用法

MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现&#xff08;两者等价&#xff09;&#xff0c;用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例&#xff1a; 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

#Uniapp篇:chrome调试unapp适配

chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器&#xff1a;Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...