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

事件队列 事件循环 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.hqwc.cn/news/586809.html

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

相关文章

汉语语音基本特性

发音的生理基础和过程 人的发音生理机构如图 2.3.1所示,发音时由肺部收缩送出一股直流空气,经气管流至喉头声门处(声门即声带开口处),在发声之初,声门处的声带肌肉收缩,声带并拢间隙小于 1mm,这股直流空气冲过很小的缝隙,使声带得到横向和纵向的速度,此时,声带向两边运动,缝隙…

蓝桥杯真题:数字三角形

import java.util.Scanner; // 1:无需package // 2: 类名必须Main, 不可修改public class Main {public static void main(String[] args) {Scanner scan new Scanner(System.in);//在此输入您的代码...int nscan.nextInt();//输入行数nint[][] arr new int[n1][n1];//存储数…

二叉树 - 栈 - 计数 - leetcode 331. 验证二叉树的前序序列化 | 中等难度

题目 - 点击直达 leetcode 331. 验证二叉树的前序序列化 | 中等难度1. 题目详情1. 原题链接2. 基础框架 2. 解题思路1. 题目分析2. 算法原理方法1:栈方法2:计数 3. 时间复杂度 3. 代码实现方法1:栈方法2:计数 leetcode 331. 验证二…

STM32 | 通用同步/异步串行接收/发送器USART带蓝牙(第六天原理解析)

STM32 第六天 一、 USART 1、USART概念 USART:(Universal Synchronous/Asynchronous Receiver/Transmitter)通用同步/异步串行接收/发送器 USART是一个全双工通用同步/异步串行收发模块,该接口是一个高度灵活的串行通信设备 处理器与外部设备通信的两种方式: u并行通信(…

为“自研”的KV数据库编写JDBC驱动

一觉醒来,受到梦的启发,自研了一套K/V数据库系统,因为"客户"一直催促我提供数据库的JDBC驱动,无奈之下,只好花费一个上午的时间为用户编写一个。 我们知道,JDBC只定义一系列的接口, 具体的实现需…

《Python之路:系统自学指南》

引言 在当今信息时代,编程已经成为一项越来越重要的技能。而Python作为一门功能强大、易学易用的编程语言,受到了越来越多人的青睐。然而,学习Python并不是一蹴而就的事情,尤其是对于没有编程基础的初学者来说,往往需…

【SQL】1633. 各赛事的用户注册率(COUNT函数 表达式用法)

题目描述 leetcode题目:1633. 各赛事的用户注册率 Code select contest_id, round(count(*)/(select count(*) from Users)*100, 2) as percentage from Register group by contest_id order by percentage desc, contest_id ascCOUNT()函数 COUNT函数用法&#…

Java的编程之旅44——学生信息管理系统

目录 1.MVC设计模式初探 文件结构的搭建 2.Student类用来初始化学生信息 3.主函数里的两个功能 1.调用初始化学生信息的功能 2.输出欢迎界面功能 4.Global类中方法的编写 5.StuPage类,StuCtrl类,StuModel类中方法的编写 1.查询功能 selStu方法的…

关于 C/C++ 1Z(17)开源项目 openppp2 协同程式切换工作流

下述为开源项目 openppp2(github)构建工作在 C/C 17 的 stackful 有栈协同程式的工作流切换示意图: 在 openppp2 之中采用人工手动方式管理协同程式之间的切换,每个中断过程只是保存线程栈信息(如寄存器、当前#PC EIP&…

【Java 集合进阶】单练集合顶层接口collction迭代器

🍬 博主介绍👨‍🎓 博主介绍:大家好,我是 hacker-routing ,很高兴认识大家~ ✨主攻领域:【渗透领域】【应急响应】 【Java】 【VulnHub靶场复现】【面试分析】 🎉点赞➕评论➕收藏 …

枚举---算法

1、定义 枚举算法:也称之为穷举算法,这种算法就是在解决问题的时候去使用所有的方式去解决这个问题,会通过推理去考虑事件发生的每一种可能,最后推导出结果。优点:简单粗暴,它暴力的枚举所有可能&#xff…

hxp CTF 2021 - A New Novel LFI(新颖的解法)

一、环境 unbentu,docker https://2021.ctf.link/assets/files/includers%20revenge-25377e1ebb23d014.tar.xz 二、解析 PHP Filter 当中有一种 convert.iconv 的 Filter ,可以用来将数据从字符集 A 转换为字符集 B ,其中这两个字符集可以…