一篇文章搞明白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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

腾讯云轻量应用服务器优惠购买攻略,怎么购买腾讯云优惠划算?

腾讯云轻量应用服务器(Lighthouse)是一款专为中小型企业和个人开发者打造的云服务器产品。它具备简单易用、成本低廉和高性能等特点,为用户提供了便捷高效的云服务器解决方案。 腾讯云轻量应用服务器采用了简单直观的图形化界面,…

linux grub2 不引导修复 grub2-install:error:/usr/lib/grub/x86_64-efi/modinfo.sh

系统部署在物理机上,开机后一直pxe不进系统,怀疑GRUB丢失。 查看bios 里 采用uefi 启动方式, 无硬盘系统引导选项, 且BMC设置为硬盘永久启动也无效。 挂载光驱ISO进入救援模式,sda为系统盘,重装grub报错 grub2-inst…

ProtoBuf的学习和使用(C++)

ProtoBuf的学习和使用---C ⼀、初识ProtoBuf序列化和反序列化的概念ProtoBuf是什么?ProtoBuf工作特点 二、主要学习思路三、快速上手四、proto3语法详解1.字段规则2.消息类型的定义与使⽤实际操练 3.enum枚举类型enum注意事项enum实操 4.Any类型Any类型实操 5.oneof类型oneof类…

FTP网络问题排查

Linux探测路径MTU&#xff1a; ping大包&#xff1a; [test]$ ifconfig eth0: flags4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1280 [test]$ ping -M do -s 1252 172.18.98.3 PING 172.18.98.3 (172.18.98.3) 1252(1280) bytes of data. 1260 bytes from 172.18.98.3: …

早上好问候语,清晨阳光暖心的早安问候语录

1、在我们每一个人的生命里&#xff0c; 会遇到各种各样的陪伴。陪伴很温暖&#xff0c; 相识不易&#xff0c;陪伴更是一种缘分&#xff01;祝福每一位朋友&#xff0c; 在人生的岁月里都能相伴而行&#xff0c; 一起度过美好的快乐时光&#xff01; 2、天天问候&#xff0c;真…

日志及其框架

日志技术的概述 日志 生活中的日志&#xff1a; 生活中的日志就好比日记&#xff0c;可以记录你生活的点点滴滴。 程序中的日志&#xff1a; 程序中的日志可以用来记录程序运行过程中的信息&#xff0c;并可以进行永久存储。 以前记录日志的方式&#xff08;输出语句&#…

为什么要安装田间气象站?

随着农业科技的发展&#xff0c;越来越多的农民朋友开始关注如何利用科技手段来提高农业生产效益。其中&#xff0c;安装田间气象站成为了许多农民朋友的选择之一&#xff0c;为什么会有这种情况呢&#xff1f;安装田间气象站会带来哪些优势呢&#xff1f; 一、了解气候变化 气…

响应式珠宝首饰展示网站模板源码带后台

模板信息&#xff1a; 模板编号&#xff1a;6201 模板编码&#xff1a;UTF8 模板颜色&#xff1a;黑白 模板分类&#xff1a;服饰、箱包、礼品、玩具 适合行业&#xff1a;珠宝饰品类企业 模板介绍&#xff1a; 本模板自带eyoucms内核&#xff0c;无需再下载eyou系统&#xf…

实现资产与财务的无缝对接,易点易动固定资产管理系统帮您消除数据难题

在现代企业中&#xff0c;固定资产管理和财务管理是两个密不可分的环节。然而&#xff0c;许多企业面临着固定资产和财务数据不一致、不准确的问题&#xff0c;给企业的决策和运营带来了困扰。为了解决这一难题&#xff0c;易点易动固定资产管理系统应运而生。该系统通过实现资…

基于C#开发的任天堂 Switch 开源模拟器

今天给大家推荐一款基于C#开发的任天堂 Switch 开源模拟器&#xff0c;可方便开发人员来测试游戏&#xff0c;也用于娱乐。 01 项目简介 Ryujinx 是一个开源的任天堂 Switch 模拟器&#xff0c;可以在 PC 上模拟运行 Switch 游戏。采用C#开发&#xff0c;基于 .NET Core技术框…

3.6、linux调试器:gdb

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 背景 程序员在做项目写代码时&#xff0c;每完成一个功能&#xff0c;需要自己先测试一下&#xff0c;看看能不能跑之类的&#xff0c;然后交给测试人员&#xff0c;但是测试人员就代表着用户&#xff0c;用户不需要调试&am…

区块链链游合约系统开发项目模式技术方案

​随着区块链技术的发展&#xff0c;链游合约系统开发逐渐成为了一个备受关注的项目。本文将探讨区块链链游合约系统开发项目的技术方案&#xff0c;包括项目背景、开发目标、技术架构、系统流程、安全措施等方面的内容。 一、项目背景 链游是一种基于区块链技术的游戏&#xf…

压测必经之路,Jmeter分布式压测教程!

01、分布式压测原理 Jemter分布式压测是选择其中一台作为调度机&#xff08;master&#xff09;&#xff0c;其他机器作为执行机&#xff08;slave&#xff09;&#xff1b;当然一台机器也可以既做调度机&#xff0c;也做执行机。 调度机执行脚本的时候&#xff0c;master将会…

NFTScan | 11.06~11.12 NFT 市场热点汇总

欢迎来到由 NFT 基础设施 NFTScan 出品的 NFT 生态热点事件每周汇总。 周期&#xff1a;2023.11.06~ 2023.11.12 NFT Hot News 01/ 《辛普森一家》提及 NFT 及区块链&#xff0c;相关 NFT 地板价涨至 0.35 ETH 11 月 6 日&#xff0c;据 Coindesk 报道&#xff0c;美国时间周…

【算法与数据结构】491、LeetCode递增子序列

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;本题和【算法与数据结构】78、90、LeetCode子集I&#xff0c; II中90.子集II问题有些类似&#xff0c;…

车载测试和软件测试有什么区别

车载测试和软件测试都是在汽车电子系统中进行的测试工作&#xff0c;但是它们之间有一些不同之处。 1. 测试对象不同&#xff1a;车载测试是在汽车电子系统中进行的测试工作&#xff0c;测试对象是整个车辆上的各种部件和系统的集成。而软件测试是针对汽车电子系统中的软件程序…

前端框架图谱

以上图谱基于个人经验总结&#xff0c;比如小程序、第三方平台等未在其中有所体现

【学习辅助】Axure手机时间管理APP原型,告别手机控番茄任务模板

作品概况 页面数量&#xff1a;共 30 页 兼容软件&#xff1a;Axure RP 9/10&#xff0c;不支持低版本 应用领域&#xff1a;时间管理、系统工具 作品申明&#xff1a;页面内容仅用于功能演示&#xff0c;无实际功能 作品特色 本品为「手机时间管理」APP原型&#xff0c;…

Django——路由层

一. 路由匹配 1. 路由匹配注意事项 urlpatterns [url(r^admin/, admin.site.urls),# 首页url(r^$,views.home),# 路由匹配url(r^test/$,views.test),url(r^testadd/$,views.testadd),# 尾页(了解): 后期使用异常捕获处理, 这样的尾页让django的第二次在路径中斜杠APPEND_SL…

【深度学习实验】网络优化与正则化(三):随机梯度下降的改进——Adam算法详解(Adam≈梯度方向优化Momentum+自适应学习率RMSprop)

文章目录 一、实验介绍二、实验环境1. 配置虚拟环境2. 库版本介绍 三、实验内容0. 导入必要的库1. 随机梯度下降SGD算法a. PyTorch中的SGD优化器b. 使用SGD优化器的前馈神经网络 2.随机梯度下降的改进方法a. 学习率调整b. 梯度估计修正 3. 梯度估计修正&#xff1a;动量法Momen…