浏览器事件循环(事件轮询)

浏览器事件循环(事件轮询)

文章目录

  • 浏览器事件循环(事件轮询)
    • 1.浏览器事件循环流程
    • 2.同步任务、异步任务、宏任务和微任务概念
        • 同步任务:
        • 异步任务:
        • 宏任务:
        • 微任务:
    • 3.宏任务和微任务区别
        • 异步任务的分类:
        • 异步任务执行顺序:
    • 4.Vue中涉及事件循环
    • 5.$nextTick

1.浏览器事件循环流程

浏览器事件循环(Browser Event Loop)是浏览器用于处理用户输入、网络请求、渲染和其他异步事件的机制。这个循环确保了 JavaScript 代码的执行是非阻塞的,允许浏览器同时处理多个任务,从而提高用户体验。以下是浏览器事件循环的详细说明:

  1. 调用栈: 当一个 JavaScript 脚本开始执行时,它会被放入调用栈。调用栈是一个数据结构,用于跟踪执行上下文(函数调用)的堆栈。

  2. 同步任务: 在调用栈中的代码是同步任务,它们会按照执行的顺序逐一执行。如果有函数调用,它们会被压入调用栈,直到执行完成。

  3. 异步任务触发: 当浏览器遇到异步任务,例如定时器、事件监听器、网络请求等,它会将这些任务放入任务队列中。

  4. 任务队列: 任务队列是一个先进先出(FIFO)的数据结构,用于存储异步任务。有多个任务队列,其中包括宏任务队列和微任务队列)。

    • 宏任务队列: 包括 DOM 操作、用户交互事件、定时器等。宏任务完成后,会将一个新的同步任务放入调用栈。

    • 微任务队列: 包括 Promise 回调、MutationObserver 回调等。微任务会在当前宏任务执行完成后、下一个宏任务执行前执行。

  5. 事件循环(Event Loop): 当调用栈为空时,事件循环开始工作。它会检查宏任务队列,如果有任务,将任务推入调用栈执行。执行完毕后,再检查微任务队列,如果有微任务,将其依次推入调用栈执行。这个过程会一直重复,形成一个循环。

    • 宏任务执行: 从宏任务队列中选择一个任务,执行完毕后,再选择下一个宏任务。

    • 微任务执行: 在宏任务执行完毕后,依次执行微任务队列中的所有任务。

这个事件循环的机制确保了 JavaScript 的异步执行,同时避免了阻塞主线程。这对于处理用户交互、网络请求等异步任务是非常重要的,以确保应用程序的响应性和性能。

2.同步任务、异步任务、宏任务和微任务概念

同步任务:

同步任务是按照它们被调用的顺序依次执行的任务,一个接一个地在调用栈中运行。在执行同步任务时,JavaScript 引擎会一直等待任务执行完毕,然后才继续执行下一个任务。

console.log('Task 1');
console.log('Task 2');
console.log('Task 3');
// ...
异步任务:

异步任务是不会阻塞后续代码执行的任务。它们将在将来的某个时间点执行,可以是由浏览器环境触发的事件,也可以是由开发者手动触发的异步操作。

// 异步任务示例:定时器
setTimeout(function() {console.log('1000ms');
}, 1000);// 异步任务示例:事件监听器
document.addEventListener('click', function() {console.log('点击');
});
宏任务:

宏任务是由浏览器环境提供的任务,包括 I/O 操作、渲染、事件处理等。在事件循环的每一轮中,只会执行一个宏任务。常见的宏任务包括 setTimeout、setInterval、DOM 操作、AJAX 请求等。

// 宏任务示例:setTimeout
setTimeout(function() {console.log('2000ms');
}, 2000);// 宏任务示例:AJAX 请求
fetch('https://api.abc.com/data').then(response => response.json()).then(data => console.log('AJAX'));
微任务:

微任务是在当前宏任务执行完毕后、下一个宏任务执行前触发的任务。它们有着更高的优先级,会在宏任务中的异步操作之前执行。常见的微任务包括 Promise 的回调、MutationObserver 等。

// 微任务示例:Promise
Promise.resolve().then(function() {console.log('微任务1');
});// 微任务示例:MutationObserver
const observer = new MutationObserver(function() {console.log('微任务2');
});observer.observe(document.body, { attributes: true });document.body.setAttribute('class', 'some-class');

在事件循环中,首先执行当前调用栈中的同步任务,然后检查并执行宏任务队列中的一个宏任务,接着执行微任务队列中的所有微任务。这个过程会一直重复,确保了 JavaScript 引擎的异步执行和非阻塞特性。

3.宏任务和微任务区别

宏任务和微任务都是异步任务的一种,但它们之间存在一些区别。

异步任务的分类:
  1. 宏任务: 包括整体的代码、setTimeout、setInterval、AJAX 请求、DOM 操作等。宏任务会在当前调用栈执行完毕后,从宏任务队列中取出一个任务执行。

  2. 微任务: 包括 Promise 的回调、MutationObserver、process.nextTick 等。微任务会在当前宏任务执行完毕后、下一个宏任务执行前触发,且微任务会在宏任务中的异步操作之前执行。

异步任务执行顺序:
  1. 执行同步任务,按照代码顺序逐一执行。
  2. 执行当前宏任务,从宏任务队列中取出一个任务执行。
  3. 执行微任务队列中的所有微任务。
  4. 重复步骤 2 和 3,直到宏任务队列为空。
console.log('同步 1');// 宏任务
setTimeout(function() {console.log('宏任务 1');// 微任务Promise.resolve().then(function() {console.log('微任务 1');});
}, 0);// 宏任务
setTimeout(function() {console.log('宏任务 2');// 微任务Promise.resolve().then(function() {console.log('微任务 2');});
}, 0);console.log('同步 2');
//同步 1
//同步 2
//宏任务 1
//微任务 1
//宏任务 2
//微任务 2

在上面的示例中,同步任务(同步1、同步2)首先执行,然后是两个宏任务(宏任务1、宏任务2)。在每个宏任务执行后,会依次执行微任务(微任务1、微任务2)。这种执行顺序确保了微任务比宏任务更具优先级,微任务会在下一个宏任务之前执行。

  1. 首先,执行同步代码,输出 ‘同步 1’ 和 ‘同步 2’。
  2. 然后,两个 setTimeout 中的回调函数被分别添加到宏任务队列。
  3. 接着,执行微任务队列中的任务,即两个 Promise 的回调函数。输出 ‘微任务 1’ 和 ‘微任务 2’。
  4. 再次回到宏任务队列,执行第一个 setTimeout 的回调函数,输出 ‘宏任务 1’。在这个宏任务中,又产生了一个微任务,即 Promise 的回调函数,输出 ‘微任务 1’。
  5. 继续执行宏任务队列,执行第二个 setTimeout 的回调函数,输出 ‘宏任务 2’。同样,在这个宏任务中,产生了一个微任务,即 Promise 的回调函数,输出 ‘微任务 2’。

微任务总是在当前宏任务执行完毕后、下一个宏任务执行前执行。微任务 1 和 微任务 2 在它们所属的宏任务(setTimeout 的回调函数)执行完毕后才得以执行。

4.Vue中涉及事件循环

在Vue.js中,事件循环主要涉及到Vue实例的生命周期、响应式数据的更新、以及Vue异步操作的处理。

  1. Vue生命周期钩子:

    • Vue实例在创建、挂载、更新、销毁等阶段都有对应的生命周期钩子函数。
    • 这些生命周期钩子函数在特定的时机被触发,它们在事件循环中的执行顺序受到影响,从而影响Vue实例的行为。
    • 例如,在created生命周期钩子中,Vue实例已经创建,但尚未挂载到DOM中。在这个阶段,可以进行一些异步操作,这些异步操作会在事件循环的下一个周期中执行。
  2. 数据更新响应:

    • Vue的响应式系统通过数据的变化来触发视图的更新。
    • 当数据发生变化时,Vue会通过事件循环的微任务队列将更新操作推送到队列中,然后在当前任务执行完成后立即执行微任务队列中的更新操作。
    • 这保证了数据更新的响应性,同时避免了在同一个任务中频繁地进行DOM更新,提高了性能。
  3. Vue.nextTick方法:

    • Vue.nextTick是Vue提供的一个工具方法,用于在DOM更新后执行回调函数。
    • 在某些场景下,比如修改了数据但想要立即获取更新后的DOM状态,可以使用Vue.nextTick来确保在下一次事件循环中执行回调。
    • 这是因为DOM更新是异步的,Vue.nextTick会将回调函数推送到微任务队列中,确保在DOM更新后执行。
  4. 异步组件加载:

    • Vue支持异步组件加载,通过import语法实现。当使用异步组件时,组件的加载是异步的。
    • 异步组件的加载过程涉及到事件循环,确保在组件加载完成后才会进行渲染。
    • 这有助于提高应用的性能,避免一开始就加载所有组件,而是按需加载。
  5. Vue异步操作:

    • 在Vue中,一些异步操作,比如$nextTick$set等,都涉及到事件循环的概念。
    • 通过这些异步操作,Vue能够在下一个事件循环周期中执行一些需要等待的任务,以确保在适当的时机进行DOM更新或其他操作。

5.$nextTick

在Vue中,一个经典的例子是使用this.$nextTick来确保在DOM更新完成后执行一些操作。这在处理DOM更新的时候非常有用,特别是当需要获取更新后的DOM状态时。

假设有一个按钮,点击按钮后触发显示一个Element UI的Modal对话框,并且想在Modal对话框显示后获取它的某些属性,例如宽度。

<template><div><el-button @click="showModal">显示Modal</el-button><el-dialog :visible.sync="dialogVisible" title="我是一个Dialog"><!-- Modal 内容 --><!-- ... --></el-dialog></div>
</template><script>
export default {data() {return {dialogVisible: false,modalWidth: null};},methods: {showModal() {this.dialogVisible = true;// 此时 Modal 还未渲染到 DOM 上console.log('Modal 尚未渲染到 DOM 上,此时宽度为:', this.modalWidth);// 使用 $nextTick 来确保在下一次事件循环中执行回调this.$nextTick(() => {// 此时 Modal 已经渲染到 DOM 上this.modalWidth = this.$refs.dialog.$el.clientWidth;console.log('Modal 已渲染到 DOM 上,宽度为:', this.modalWidth);});}}
};
</script>

当按钮被点击时,showModal方法会设置dialogVisibletrue,显示Modal。然后使用this.$nextTick来确保在下一次事件循环中执行回调函数,这个回调函数用于获取Modal对话框的宽度。通过这种方式,能够确保在Modal渲染到DOM上后再去获取其属性,避免了在Modal还未渲染完成时就尝试获取其属性的问题。

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

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

相关文章

从事铁路工作保护足部,穿什么劳保鞋更安全

铁路运输在我国交通运输业中起着骨干作用&#xff0c;为国民经济的可持续发展和人口流动做出了巨大贡献。安全是铁路运输不可忽视的问题&#xff0c;在作业场地随处能见到“安全就是生命&#xff0c;责任重于泰山”的安全标语&#xff0c;由此可见安全问题是放在首位的。 铁路施…

PyTorch深度学习实战(30)——Deepfakes

PyTorch深度学习实战&#xff08;30&#xff09;——Deepfakes 0. 前言1. Deepfakes 原理2. 数据集分析3. 使用 PyTorch 实现 Deepfakes3.1 random_warp.py3.2 Deepfakes.py 小结系列链接 0. 前言 Deepfakes 是一种利用深度学习技术生成伪造视频和图像的技术。它通过将一个人的…

用python实现word中所有图片变清晰

要使用Python将Word文档中的所有图片变清晰&#xff0c;你需要使用一些库&#xff0c;例如python-docx和OpenCV。以下是一个简单的示例&#xff0c;说明如何使用这些库来提高Word文档中图片的清晰度。 请注意&#xff0c;这种方法基于简单的图像增强技术&#xff0c;可能无法提…

学习Vue配置代理总结

今天学习了Vue的配置代理&#xff0c;当我们想要向服务器取回来数据时就先要向服务器发送请求&#xff0c;但前端发送请求的方式也有很多种&#xff0c;首先是发送请求的鼻祖JS的XMLHttpRequest&#xff08;xhr&#xff09;&#xff0c;它操作起来相对麻烦&#xff0c;开发中也…

SpringBoot自定义Starter(@EnableXXX和META-INF的SPI自动添加)

目录 1. 自定义Starter1.1 场景和效果1.2 starter实现1.2.1 创建自定义starter项目1.2.2 把所有maven依赖导入1.2.3 实现公共代码逻辑1.2.4 添加方式一&#xff1a;实现RobotAutoConfiguration配置类1.2.5 添加方式二&#xff1a;实现RobotAutoConfiguration配置类 EnableRobo…

大数据日志数据量过大如何处理

如果是web端的埋点数据&#xff0c;我们可以对这些数据进行分流。 我们可以采用事件分流&#xff0c;步骤如下 定义事件类型&#xff1a; 根据埋点数据的内容&#xff0c;定义不同的事件类型。例如&#xff0c;可以有页面访问事件、按钮点击事件、表单提交事件等。 提取关键信…

Linux下如何快速调试I2C设备

Linux下如何快速调试I2C设备 目录 1 什么场景下需要快速调试I2C设备 2 如何快速调试I2C设备 3 如何获取I2C Tools工具集 3.1 获取I2C Tools工具集源码 3.2 编译I2C Tools工具集源码 3.3 为设备添加I2C Tools工具集 4 如何使用I2C Tools工具集 5 小结 1 什么场景下需要快…

强化app广告变现用户隐私合规,移动广告变现合规技巧

移动广告技术的发展帮助开发者极大提升了广告变现效率&#xff0c;APP作为用户个人信息处理的重要载体&#xff0c;自从《个人信息保护法》颁布以来&#xff0c;个人信息的使用已经成为监管重点&#xff0c;开发者强化合规意识&#xff0c;让广告变现业务“细水长流”&#xff…

Ansible Filter滤波器的使用

一、【说在前面】 Ansible Filter一般被称为滤波器或者叫过滤器。 这个东西初次听到以为是什么科学计算的东西&#xff0c;但是想来ansible不太可能有什么滤波操作&#xff0c;所以这个东西本质是一个数值筛选器&#xff0c;内置函数&#xff0c;本质是一个为了做区别化的工具…

AcrelEMS-CB商业建筑能源管理系统解决方案-安科瑞 蒋静

1概述 AcrelEMS-CB商业建筑能源管理系统&#xff0c;集电力监控、电能质量监测与治理、电气安全预警、能耗分析、照明控制、新能源使用、能源收费以及设备运维等功能于一体&#xff0c;通过一套系统对商业建筑的能源进行统一监控、统一运维和调度&#xff0c;系统可以通过WEB和…

QT基础篇(6)QT5图形与图片

1.QT5位置相关函数 在Qt5中&#xff0c;有一些与位置相关的函数可以帮助您处理窗口和控件的位置。下面是一些常用的位置相关函数&#xff1a; move(x, y): 将窗口或控件移动到屏幕上的指定位置&#xff0c;其中x和y表示要移动到的坐标。 resize(width, height): 调整窗口或控…

go切片参数传递用值还是指针

Go 中常用的切片 slice 数据结构是动态数组&#xff0c;切片长度并不固定&#xff0c;在容量不足的时候会自动扩容。 切片实质上是对一个底层数组的抽象视图&#xff0c;由 Go 运行时维护。在运行时&#xff0c;切片由如下的 SliceHeader 结构体表示&#xff0c;其中 Data 字段…

机器人说明书---名词解释030课_python语言_方法重写

这里写自定义目录标题 方法重写类属性与方法类的私有属性类的方法类的私有方法实例类的私有方法实例如下&#xff1a; 类的专有方法&#xff1a;视频讲解 方法重写 如果你的父类方法的功能不能满足你的需求&#xff0c;你可以在子类重写你父类的方法&#xff0c;实例如下&…

【极光系列】springBoot集成Hibernate

【极光系列】springboot集成hibernate gitee地址 直接下载可用 https://gitee.com/shawsongyue/aurora.git 模块&#xff1a;aurora_hibernate mysql安装教程 参考我另外一篇文章&#xff0c;直接下载安装 https://blog.csdn.net/weixin_40736233/article/details/1355829…

数据库负载均衡部署(使用ipvadm ,docker)

文章目录 … 要在Docker中使用IPVS配置MariaDB数据库的高可用集群&#xff0c;并设置VIP地址为192.168.201.4&#xff0c;密码全部设为123456你可以按照以下步骤进行操作&#xff1a; 第一步 创建一个docker网络 docker network create --subnet192.168.200.0/24 mariadb_netw…

FPGA 原理图细节--画引脚

BGA引脚表示 1.1 FPGA此引脚要正确和清晰&#xff0c;会在“Package Pin”中用到次物理接口 1.2, MCU 只用管对应的GPIO逻辑接口就可以了 标识Bank电平 标识出对应Bank的电平&#xff0c;在电路设计中可以清晰的知道对应的脚位输出电平。在"IO std"也方便的选择 Ea…

芯片设计重要工具—— IBM LSF 分布式高性能计算调度平台

IBM Spectrum LSF Suites 是面向分布式高性能计算 (HPC) 的工作负载管理平台和作业调度程序。基于 Terraform 的自动化现已可用&#xff0c;该功能可在 IBM Cloud 上为基于 IBM Spectrum LSF 的集群供应和配置资源。 借助我们针对任务关键型 HPC 环境的集成解决方案&#xff0…

常见的限流算法

本文已收录至我的个人网站&#xff1a;程序员波特&#xff0c;主要记录Java相关技术系列教程&#xff0c;共享电子书、Java学习路线、视频教程、简历模板和面试题等学习资源&#xff0c;让想要学习的你&#xff0c;不再迷茫。 天下武学出同源 正所谓天下武学殊途同归&#xff…

fgetc函数和fputc函数

目录 getchar和putchargetc和putcfgetc和fputc 橙色 getchar和putchar int getchar(void); // 从标准输入 stdin 获取一个字符&#xff08;一个无符号字符&#xff09;。这等同于 getc 带有 stdin 作为参数int putchar(int char); // 把参数 char 指定的字符&#xff08;一个…

N5181A/安捷伦Agilent N5181A信号发生器

181/2461/8938产品概述&#xff1a; 规格&#xff08;说明书&#xff09;&#xff1a;表示已校准的仪器在工作温度范围0-55C内存放至少2小时&#xff0c;除非另有说明&#xff0c;并经过45分钟预热期后的保证性能。的指标包括测量不确定度。除非另有说明&#xff0c;本文档中的…