事件队列事件循环(EventLoop) 宏任务 微任务详解 面试题

news2024/11/25 22:32:16

事件队列 事件循环 EventLoop 宏任务 微任务详解

  • 一、概念
  • 二、宏任务(多个)、微任务(1个)
  • 三、Promise 的构造函数
  • 四、process.nextTick在事件循环中的处理
  • 五、vue nextTick原理

一、概念

event: 事件
loop: 循环,循环的是一个又一个的任务队列
任务队列: 是一个先进先出的数据结构, 排在前面的事件, 优先被主进程读取
任务队列分为: 宏队列, 微队列, 分别存放在宏任务和微任务

ES6 规范中,microtask 称为 jobs,macrotask 称为 task,宏任务是由宿主发起的,而微任务由JavaScript自身发起。

二、宏任务(多个)、微任务(1个)

我们常见的点击和键盘等事件也宏任务

  1. 常见的宏任务
  • setTimeout()
  • setInterval()
  • setImmediate()
  • script
  1. 常见的微任务
  • promise.then()
  • promise.catch()
  • new MutaionObserver()
  • process.nextTick()
  1. 本质区别
    宏任务特征: 有明确的异步任务需要执行和回调; 需要其他异步线程支持。
    微任务特征: 没有明确的异步任务需要执行,只有回调;不需要其他异步线程支持。

  2. 执行顺序(这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop 事件循环)
    console.log = promise -> promise.nextTick -> promise.then -> setTimeout -> setImmediate
    ①先按代码顺序将同步任务压入主执行栈中执行
    ②遇到异步任务则先将异步任务压入对应的任务队列中(宏队列或微队列)
    ③同步任务执行完毕后,查看微队列,将微任务一一取出进入主执行栈中执行
    ④微任务队列清空后,再查看宏队列,只取出第一个宏任务执行,执行完

  • 首先我们分析有多少个宏任务;
  • 在每个宏任务中,分析有多少个微任务;
  • 根据调用次序,确定宏任务中的微任务执行次序;
  • 确定整个顺序。
    then中的回调函数要确定Promise状态后才能压入微队列

Event Loop 在压入事件时,都会判断微任务队列是否还有需要执行的事件:如果有,则优先将需要执行的微任务压入;没有,则依次压入需要执行宏任务!
事件循环 宏任务 微任务 示意图
事件循环 宏任务 微任务 示意图

//  Promise 中的执行顺序
const promise = new Promise(function(resolve, reject) {
  console.log('Promise');
  resolve();
});

promise.then(() => {
  console.log('resolved');
});

console.log('Hi!'); // Promise Hi!resolved
// 执行顺序
setTimeout(function () {
  console.log(1);
});

new Promise(function (resolve,reject) {
  console.log(2);
  resolve(3);
}).then(function (val) {
  console.log(val);
  new Promise((resolve,reject) => {
    console.log(5);
    resolve(7);
  }).then(function (val) {
    console.log(val);
  });
});
console.log(4);

// 先按顺序执行同步任务
// Promise 新建后立即执行输出2, 接着输出4, 异步任务等同步任务执行完成后执行
// 且同一次事件循环中, 微任务永远在宏任务之前执行。这时候执行栈空了,执行事件队列,
// 先取出微任务, 输出3, 最后取出宏任务, 输出1

三、Promise 的构造函数

Promise 构造函数是 JavaScript 中用于创建 Promise 对象的内置构造函数。
Promise 构造函数接受一个函数作为参数,该函数是同步的并且会被立即执行,所以我们称之为起始函数。起始函数包含两个参数 resolve 和 reject,分别表示 Promise 成功和失败的状态。
起始函数执行成功时,它应该调用 resolve 函数并传递成功的结果。当起始函数执行失败时,它应该调用 reject 函数并传递失败的原因。
Promise 构造函数返回一个 Promise 对象,该对象具有以下几个方法:
then:用于处理 Promise 成功状态的回调函数。
catch:用于处理 Promise 失败状态的回调函数。
finally:无论 Promise 是成功还是失败,都会执行的回调函数。
当 Promise 被构造时,起始函数会被同步执行;

四、process.nextTick在事件循环中的处理

process.nextTick是Node环境的变量,process.nextTick() 是一个特殊的异步API,其不属于任何的Event Loop阶段。事实上Node在遇到这个API时,Event Loop根本就不会继续进行,会马上停下来执行process.nextTick(),这个执行完后才会继续Event Loop。所以,nextTick和Promise同时出现时,肯定是process.nextTick() 先执行。

可以类比 Vue.$nextTick(),也是需要执行完这个函数后,才能继续Event Loop。

五、vue nextTick原理

Vue.nextTick() 是一个方法,用于在下次 DOM 更新循环结束之后执行延迟回调。它的实现原理是利用浏览器的异步任务队列机制,在 tick 时刻将回调函数放入队列中等待执行。在实现上,nextTick 方法会根据当前环境选择不同的底层实现。在现代浏览器中,它使用了 MutationObserver 和 Promise 等技术实现异步任务调度;在旧版浏览器中,则使用了 setTimeout 来模拟异步任务。

Vue.nextTick()的实现原理主要是将回调函数推入到一个队列中,在下一个事件循环周期(MacroTask)中执行这个队列中的所有回调函数。具体来说,当用户使用 Vue.nextTick()执行回调函数时,Vue.js 会按照以下步骤进行处理:

1.首先,Vue.js 会将回调函数推入到一个队列中。这个队列称为“异步更新队列”(Async Queue),它是 Vue.js 用于收集在同一事件循环周期内需要执行的所有异步任务的容器。
2.接着,Vue.js 会判断当前是否存在一个微任务(MicroTask)队列。如果存在,则将异步更新队列合并到微任务队列中;否则,创建一个新的微任务队列,并将异步更新队列添加到其中。
3.接着,Vue.js 会将当前执行上下文捕获并保存下来。这个上下文包含了当前执行 Vue.nextTick()方法的组件实例、数据变化等信息。
4.最后,Vue.js 会将一个微任务添加到微任务队列中。这个微任务的作用是在下一个事件循环周期中执行异步更新队列中的所有回调函数,并且在执行之前恢复上下文,确保回调函数能够正确地访问到相关数据。

// 下面是一个简单的示例代码,演示了 Vue.nextTick()的使用方法和实现原理:
// 定义一个 Vue 实例
var vm = new Vue({
  el: '#app',
  data: {
    message: 'Hello, world!',
  },
});

// 在数据更新后执行回调函数
vm.message = 'Hello, Vue.js!';
Vue.nextTick(function () {
  console.log('DOM updated!');
});
// 输出:'DOM updated!'

在这个示例中,我们首先定义了一个 Vue 实例,并通过数据绑定将 message 属性绑定到了页面上。然后,我们通过修改 message 属性的值来触发视图更新,并在 Vue.nextTick()方法中添加了一个回调函数来检查 DOM 是否已经更新。

当我们运行这段代码时,Vue.js 会按照上述步骤进行处理,并在下一个事件循环周期中执行回调函数。因此,我们可以在控制台中看到输出结果。

总的来说,Vue.nextTick()提供了一种非常方便的方式来处理 DOM 更新后的回调函数,可以帮助我们避免一些常见的问题,例如在获取 DOM 元素的位置或尺寸时可能会遇到的延迟问题。同时,它的实现也为我们提供了一种思路,

与 node 的 nextTick 的区别
Vue.nextTick和 Node.js 的process.nextTick虽然名字相似,但是它们的功能和用途不同。

Vue.nextTick是 Vue.js 提供的一个方法,主要用于在 DOM 更新之后执行某些操作,例如更新完数据后获取更新后的 DOM 节点。它利用了浏览器的异步渲染机制,将回调函数推迟到下一个 DOM 更新周期中执行。

process.nextTick是 Node.js 提供的一个方法,主要用于在当前事件循环的末尾、下一次事件循环之前执行一些操作。它可以让你在当前事件循环中的所有 I/O 操作完成后立即执行回调函数,而不必等待下一次事件循环。

因此,Vue.nextTick和process.nextTick虽然名称相似,但是它们的作用和使用场景不同,不能互相替代。

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

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

相关文章

使用Bitmaps位图实现Redis签到

系列文章目录 文章目录 系列文章目录前言前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。 Redis提供了Bitmaps这个“数据类型”可以实现对位的操作: (1) Bitmaps…

整顿编剧市场:程序员提交测试流程的最佳实践

讲动人的故事,写懂人的代码 最近,一部去年推出的国产电视剧在IT圈子里引起了轰动。 引起关注的原因,并非剧中程序员的外形出众,而是她提交代码测试的方式——将写有代码的纸张放入文件夹,然后递给了对面的测试人员。如图1所示。 图1 程序员将写有代码的纸张放入文件夹,并…

Python字符串操作方法一览表

字符串操作 你患得患失太在意从前又太担心将来,有句话说的好昨天是段历史,明天是个谜团而今天是天赐的礼物 像珍惜礼物那样珍惜今天。—— 龟大仙《功夫熊猫3》 1.字符串连接 例子: str1 "Hello" str2 "World" resul…

算法学习17:背包问题(动态规划)

算法学习17:背包问题(动态规划) 文章目录 算法学习17:背包问题(动态规划)前言一、01背包问题:1.朴素版:(二维)2.优化版:(一维&#xf…

DeepBook通过NFT空投预告Token发布

是Sui的第一个原生流动性层,正在推出自己的原生token $DEEP,巩固其作为Sui网络关键金融基础设施的地位。DEEP旨在为在DeFi中提供整体流动性的机构和机构交易者使用DeepBook。DeepBook和DEEP的结合为DeFi应用提供了首要的Web3流动性来源。 DEEP token的关…

人事管理系统的设计与实现|Springboot+ Mysql+Java+ B/S结构(可运行源码+数据库+设计文档)请假加班招聘考勤

本项目包含可运行源码数据库LW,文末可获取本项目的所有资料。 推荐阅读300套最新项目持续更新中..... 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 2024年56套包含ja…

分区合并风险大,数据恢复有妙招

分区合并,是计算机磁盘管理中的一个常见操作,旨在通过整合相邻的分区来创建一个更大的逻辑分区,从而更有效地利用磁盘空间。这种操作看似简单,但实则蕴含着不小的风险。一旦操作不当或遇到意外情况,很可能导致数据丢失…

混沌加密:探索信息安全的前沿技术

在当今数字化时代,信息安全已成为全球关注的焦点。随着网络攻击手段的日益复杂,传统的加密技术面临着严峻的挑战。为了应对这些挑战,科学家们一直在探索更为先进的加密技术,混沌加密便是其中之一。本文将对混沌加密的原理、特点以…

开源项目advcpmv实现cp/mv显示进度条 —— 筑梦之路

项目地址:https://github.com/jarun/advcpmv 1. 查看当前系统上的包版本 rpm -qa | grep -w coreutils 2. 下载8.32版本的源码包 wget http://ftp.gnu.org/gnu/coreutils/coreutils-8.32.tar.xz 3. 下载对应版本的补丁包 wget https://github.com/jarun/advcpm…

Incus:新一代容器与虚拟机编排管理引擎

Incus是什么? Incus是一个用于编排管理应用型容器、系统型容器及虚拟机实例的管理工具。它是对 Canonical LXD 的继承与发展,引入了更多的存储驱动支持。 Incus项目的产品地址:Linux Containers - Incus - Introduction 在 LXC-Incus 项目…

Runes 生态一周要览 ▣ 2024.3.25-3.31|Runes 协议更新 BTC 减半在即

Runes 生态大事摘要 1、Casey 发布了 Runes 协议文档 RUNES HAVE DOCS,Github 代码库更新到 ord 0.17.0 版本,Casey 表示符文是一个“严肃”的代币协议。 2、Casey 公布了第一个硬编码的创世符文「UNCOMMONGOODS」 3、4月7日香港沙龙|聚焦「…

【Algorithms 4】算法(第4版)学习笔记 23 - 5.4 正则表达式

文章目录 前言参考目录学习笔记1:正则表达式1.1:表示1.2:快捷表示2:正则表达式与非确定有限状态自动机 REs and NFAs2.1:二元性2.2:模式匹配实现2.3:非确定有限状态自动机 Nondeterministic fin…

mysql锁表问题

问题描述 偶尔应用日志会打印锁表超时回滚 org.springframework.dao.CannotAcquireLockException: ### Error updating database. Cause: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transactionmysql锁…

Python基础之pandas:文件读取与数据处理

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一、文件读取1.以pd.read_csv()为例:2.数据查看 二、数据离散化、排序1.pd.cut()离散化,以按范围加标签为例2. pd.qcut()实现离散化3.排序4.…

原型链污染攻击也称JavaScript Prototype 污染攻击

JavaScript数据类型 let和var关键字的区别 使用var或let关键字可以定义变量 let和var的区别如下: var是全局作用域,let 只在当前代码块内有效 当在代码块外访问let声明的变量时会报错 var有变量提升,let没有变量提升 let必须先声明…

一文秒解四大经典限流算法

阅读前提:没有最好的算法,只有最适合的算法! 限流算法: 固定窗口限流算法 滑动窗口限流算法 漏桶限流算法 令牌桶限流算法 固定窗口限流算法 介绍 固定窗口限流算法(Fixed Window Rate Limiting Algorithm&#…

算法知识点汇总

知识点 1. 求二进制中1的个数 int get_count(int x)//返回x的二进制有多少个1 int get_count(int x) {int res 0;while (x){res ;x - x & -x;}return res; }2. 建树,和树的DFS 记得初始化头节点 const int N 1e5 10, M N * 2; int h[N], e[M], ne[M], id…

【OpenCV】 基础入门(一)初识 Mat 类 | 通过 Mat 类显示图像

🚀 个人简介:CSDN「博客新星」TOP 10 , C/C 领域新星创作者💟 作 者:锡兰_CC ❣️📝 专 栏:【OpenCV • c】计算机视觉🌈 若有帮助,还请关注➕点赞➕收藏&#xff…

OR-352,兼容替代TLP187/TLP127/EL452等,达灵顿光耦

低输入正向电流 高电流传输比 DC和AC输入 电平转换 高输入输出隔离电压和高集电极发射极电压 特征 电流传输比(IF 1mA,VCE 2V时,CTR : 最小1000%) 高集电极-发射极电压 (VCEO 300V) …

mongodb的简单操作

文章目录 前言数据库的创建和删除集合的创建和删除文档的插入和查询异常处理更新数据局部修改符合条件的批量更新加操作 删除文档删除全部数据删除符合条件的数据 统计count统计有多少条数据统计特定条件有多少条数据 分页查询排序查询正则查询比较查询包含查询条件连接查询索引…