JavaScript:事件循环机制(EventLoop)

一、理解进程、线程

进程是操作系统中的基本概念之一,指的是一个正在运行中的程序,包括了程序的执行代码、数据、资源等。操作系统为每个进程分配一定的系统资源,例如内存空间、文件和设备等,以便进程能够正常运行。

线程是进程中的一个执行流程,可以看作是进程中的一个独立执行单元。每个进程中可以包含多个线程,这些线程共享进程的资源。不同于进程,线程是无法独立存在的,必须依存于进程而存在。线程通过利用进程的资源来执行任务,并可以在进程内进行切换。

简单地说,进程是资源分配和管理的最小单位,而线程是程序执行的最小单位。在多任务环境下,多个进程可以同时执行,同一个进程中的多个线程也可以同时执行。线程的切换比进程的切换开销小,因此多线程的程序更加高效。

二、理解单线程、多线程

单线程指的是程序只有一个执行线程,只能串行执行任务,即每个任务都得等前一个任务执行完毕后才能进行下一个任务。这种模式的好处是逻辑简单,开发维护成本低,但执行效率较低,特别是在处理大量数据时容易出现阻塞等问题。

多线程指的是程序同时拥有多个执行线程,每个线程可以独立运行,可以同时处理多个任务。多线程可以大大提高程序的执行效率和响应能力,特别是在需要同时处理多个任务或大量数据时非常有用。但多线程的缺点是复杂度高,容易出现并发问题,需要耗费更多的系统资源和开发成本。

单线程适用于简单的应用程序,而多线程则适用于复杂的应用程序,能够大幅提高程序的执行效率和响应能力。

三、理解渲染线程

渲染线程是指用于渲染图形的计算机进程线程。在Web浏览器中,渲染线程负责将HTML、CSS和JavaScript代码转化为网页上的可视化内容。渲染线程的主要任务是解析HTML文档,确定渲染树和绘制图像。它还负责检查和处理JavaScript代码,以便在网页上进行交互式操作。

渲染线程的作用是在不影响用户界面的情况下,尽可能快地显示用户请求的内容。它要注意避免阻塞用户界面线程,因此需要在后台运行,并尽量减少CPU和内存的使用。

在某些情况下,渲染线程可能需要等待网络请求或文件加载完成,这时可能会导致页面出现卡顿或加载缓慢的情况。为了减少这种情况的发生,渲染线程通常会使用缓存技术,以便在加载相同内容时快速显示网页。

四、理解微任务、宏任务

微任务和宏任务都是JavaScript事件循环机制中的任务类型。它们之间的区别在于执行的时机和优先级。

宏任务包括一些比较耗时的任务,例如setTimeout、setInterval、AJAX请求、DOM事件等等。这些任务执行完之后,需要等待下一次事件循环开始才能执行下一个任务。执行宏任务时,会先选取队列中最先进入队列的任务执行,直到队列为空。

微任务指的是一些比较短且需要立即执行的任务,例如Promise的then方法、MutationObserver等等。这些任务执行时,会在当前宏任务执行完毕后立即执行。当一个宏任务中产生了微任务,这些微任务会先被放到一个专门的队列中,等待当前宏任务执行完毕时再执行。而在执行这些微任务时,如果又产生了新的微任务,这些新的微任务会被放到队列的末尾,等待执行。

在事件循环开始时,先执行所有的微任务队列中的任务,直到队列为空。然后再执行宏任务队列中的任务。然后再执行微任务队列中的任务,直到队列为空。这个过程会一直重复下去,直到任务队列中和微任务队列中同时为空。

总结来说,微任务具有更高的优先级,会比宏任务优先执行。因此在编写异步代码时,应当注意使用合适的任务类型,以保证代码的正确性和效率。

六、理解同步任务、异步任务

同步任务是指代码按照顺序执行,每完成一项任务后再进行下一项任务,直到所有任务完成。在同步任务中,代码执行需要等待前一个代码执行完成后才能继续进行下一项任务。

异步任务则是指代码在执行过程中,不必等待前一个任务完成后再执行下一个任务。异步任务可以在单个线程上执行,但可以同时进行多个任务。异步任务通常使用回调函数或Promise来实现异步处理。

举个例子:假设有一个任务列表,包括读取文件、发送数据、等待响应等任务。如果使用同步任务执行,读取文件的任务必须在发送数据的任务完成后才能开始。而在异步任务中,可以在发送数据的同时执行读取文件任务,因此能够更高效地完成任务。

七、理解调用栈

调用栈是用来跟踪程序执行顺序的一种内存结构。当函数被调用时,它们的相关信息(例如局部变量,返回地址等)会被压入调用栈中,调用栈按照“先进后出”的原则运作。也就是说,当函数返回时,它们的相关信息将从栈中被弹出,以便程序继续执行。通过调用栈,我们可以跟踪程序的执行过程,查看每个函数被调用的顺序以及它们之间的关系。调用栈也是调试程序时重要的工具之一,可以帮助程序员精确定位程序中的问题。

八、JavaScript在设计时就被设计为单线程

1、简单性:单线程代码容易编写、调试和维护,不容易出现多线程竞争的问题。

2、安全性:多线程需要共享内存,容易造成数据竞争等问题。JavaScript作为一种脚本语言,通常运行在浏览器环境中,存在众多恶意脚本的威胁。如果JavaScript是多线程的,恶意脚本可能会通过共享内存的方式修改其他脚本的数据,从而造成安全问题。

3、可预测性:单线程可以确保事件的执行顺序是可预测的,从而能够避免一些复杂的并发场景。

当然,JavaScript也提供了一些非常重要的异步API,如setTimeout、setInterval、Promise、async/await等,这些API可以模拟多线程的效果,但本质上仍然是单线程。

九、JavaScript为什么需要异步

1、防止阻塞:JavaScript是单线程语言,如果所有任务都是同步执行的,当执行某个耗时操作(比如网络请求或文件读写)时,整个应用程序会被阻塞,造成用户体验不佳。

2、提升用户体验:异步编程可以使得JavaScript在执行耗时操作的同时,继续响应用户的操作,从而提升用户体验。

3、节约资源:异步编程可以更好地利用计算机资源,通过并行执行多个任务,提高执行效率。

4、支持跨平台开发:JavaScript广泛应用于Web、移动端和后端等不同平台,使用异步编程模式可以支持多种异步事件,从而使得代码具有更好的可移植性。

十、JavaScript中的异步操作有哪些

序号操作
1回调函数
2Promise
3async/await
4事件监听
5定时器
6XMLHttpRequest和Fetch API等网络请求
7Web Workers(Web Worker API提供了从主执行线程分离并在后台运行脚本的能力,即在后台运行JavaScript代码,不影响页面UI的渲染和响应能力)
8Node.js中的异步I/O操作(如读写文件、网络请求等)

十一、JavaScript单线程是如何实现异步的?理解JavaScript事件循环机制

有了前文基础我们来探讨本文核心事件循环。

JavaScript单线程指的是在同一时刻只能执行一个任务,任务只有在前一个任务执行完毕后才能开始执行。但是JavaScript通过事件循环机制实现了异步。

JavaScript事件循环机制指的是JavaScript运行时环境(ECMAScript规范定义的)按照一定的规则处理代码中的异步操作和事件的机制。JavaScript事件循环机制包含任务队列(Task)、微任务队列(Microtask)和宏任务队列(Macrotask)。

当JavaScript代码执行到一个异步操作或事件时,它并不会立即执行,而是将其放入对应的任务队列中。当当前任务执行完成后,在下一个事件循环的开始,JavaScript会从任务队列中取出一个任务,执行该任务。当任务执行时,可能会产生新的异步操作和事件,这些新的操作也会被放入任务队列中等待执行。

在JavaScript事件循环机制中,任务分为宏任务和微任务。
宏任务包括setTimeout、setInterval、I/O操作等;
微任务包括Promise、MutationObserver、process.nextTick等。
在每次事件循环开始时,JavaScript会先执行所有的微任务队列中的任务,然后再执行宏任务队列中的任务。

一个完整的事件循环流程包括以下步骤:

1. 从宏任务队列中取出一个任务执行;
2. 如果该任务中产生了微任务,将它们放入微任务队列中;
3. 执行微任务队列中的所有任务;
4. 检查是否需要重新渲染页面;
5. 重复执行上述步骤,直到任务队列和微任务队列中都没有任务;

事件循环机制是指:

1、代码执行时,先执行同步任务,然后将异步任务放入任务队列中,等待执行。
2、当所有同步任务执行完毕后,JavaScript引擎会去读取任务队列中的任务。
3、将队列中的第一个任务压入执行栈中执行,执行完毕后将其出栈。
4、如此循环执行,直到任务队列中的所有任务都执行完毕。

这就是JavaScript实现异步的基本原理,通过将异步任务放到任务队列中,并通过事件循环机制来实现异步执行。

总的来说,JavaScript通过事件循环机制来实现异步操作,将异步任务放到任务队列中,然后在任务队列中等待执行,直到JavaScript引擎空闲,再将任务队列中的任务拿出来执行。

十二、练习题

1、下面哪些操作是异步的?

下面哪些操作是异步的?a. 将数组元素进行排序
b. 发送请求获取数据
c. 计算两个数的和
d. 读取本地文件答案:b和d

2、下面的代码输出什么?

console.log('start')setTimeout(() => {console.log('timeout')
}, 0)console.log('end')答案:start, end, timeout解析:setTimeout函数中的第二个参数表示延迟的时间,当设置为0时,setTimeout函数会被放到任务队列的末尾,等待执行栈中所有任务执行完成后再执行setTimeout函数中的回调函数。

3、下面的代码输出什么?

console.log('start')setTimeout(() => {console.log('timeout1')
}, 0)new Promise((resolve) => {console.log('promise1')resolve()
}).then(() => {console.log('then1')
})console.log('end')答案:start, promise1, end, then1, timeout1解析:Promise对象是同步执行的,所以会先输出promise1。但是.then()方法是异步执行的,会被放到任务队列中等待执行,因此end会先输出。然后在任务队列中执行.then()方法,输出then1。最后在任务队列中执行setTimeout中的回调函数,输出timeout1。

4、下面代码输出什么?

console.log('start')setTimeout(() => {console.log('timeout1')Promise.resolve().then(() => console.log('then2'))
}, 0)new Promise((resolve) => {console.log('promise1')resolve()
}).then(() => {console.log('then1')setTimeout(() => {console.log('timeout2')}, 0)
})console.log('end')答案:start, promise1, end, then1, timeout1, then2, timeout2解析:同样的,Promise对象和.then()方法是同步执行的,但是回调函数中包含的Promise对象和.then()方法时异步执行的,会被放到任务队列中等待执行。因此start, promise1, end, then1会先输出。然后在任务队列中执行setTimeout中的回调函数,输出timeout1,然后将包含的Promise对象和.then()方法放到任务队列中。在任务队列中执行.then()方法,输出then2。最后在任务队列中执行第二个setTimeout中的回调函数,输出timeout2。

5、下面代码输出什么?

console.log('start'); // 1setTimeout(function() {console.log('setTimeout'); // 5
}, 0);Promise.resolve().then(function() {console.log('promise'); // 4
});console.log('end'); // 2这段代码中,我们依次执行了以下操作:打印"start"
打印"end"
创建一个Promise对象,并将其添加到微任务队列中
执行Promise中的回调函数,打印"promise"
执行setTimeout中的回调函数,打印"setTimeout"
根据JavaScript事件循环机制的规则,它的执行过程如下:全局上下文入栈,开始执行同步任务
打印"start"
全局上下文出栈
全局上下文入栈,开始执行同步任务
打印"end"
全局上下文出栈
全局上下文入栈,开始执行同步任务
创建Promise对象,并将其添加到微任务队列中
执行Promise对象中的回调函数,打印"promise"
全局上下文出栈
执行微任务队列中的任务,打印"setTimeout"
因此,最终输出结果应该是:start
end
promise
setTimeout

6、下面代码的输出结果是什么?

console.log(1);setTimeout(() => {console.log(2);
}, 0);Promise.resolve().then(() => {console.log(3);
});console.log(4);输出结果是 1 4 3 2。解析:代码执行顺序为同步任务先执行,输出1,然后将异步任务放入任务队列中。setTimeout是一个宏任务,Promise.then是一个微任务。由于Promise是微任务,会优先执行,所以先输出3。然后执行完同步任务后,会依次执行微任务。所以输出顺序为1,4,3。最后执行宏任务,输出2。

7、下面代码的输出结果是什么?

console.log("start");setTimeout(() => {console.log("setTimeout");
}, 0);Promise.resolve().then(() => {console.log("Promise");
});console.log("end");输出结果是 start end Promise setTimeout。解析:代码执行顺序同第一题,先输出同步任务 start 和 end,然后将异步任务放入任务队列中。由于Promise.then是一个微任务,所以会优先执行,输出 Promise。接着执行完同步任务后,依次执行微任务中的 Promise。最后执行宏任务 setTimeout 输出结果。

十三、过程记录

记录一、浏览器事件循环机制还是JavaScript事件循环机制

观点一

浏览器事件循环机制和JavaScript事件循环机制是一个概念,只是叫法不同。
JavaScript事件循环机制分为浏览器和Node事件循环机制,两者的实现技术不一样。浏览器Event Loop是HTML中定义的规范,Node Event Loop是由libuv库实现。JavaScript 事件循环机制分为JS调用栈和任务队列两部分。JS调用栈是一种后进先出的数据结构,当函数被调用时,会被添加到栈中的顶部,执行完成之后就从栈顶部移出该函数,直到栈内被清空。任务队列是先进先出的数据结构,当主线程空闲时,就会去任务队列中按照顺序读取一个任务放入到栈中执行。

观点二

浏览器事件循环机制和 JavaScript 事件循环机制是密切相关的。浏览器事件循环机制是指浏览器在处理各种事件(例如用户交互、网络请求、定时器等)时,如何协调执行这些事件的机制。而 JavaScript 事件循环机制则是指 JavaScript 引擎在处理异步代码时如何协调执行这些代码的机制。实际上,JavaScript 事件循环机制是建立在浏览器事件循环机制之上的。JavaScript 引擎通过调用浏览器提供的 API 来注册事件监听器,然后在事件触发时将回调函数加入任务队列。浏览器事件循环机制会不断地从任务队列中取出回调函数并执行,直到任务队列为空。因此,可以认为浏览器事件循环机制是 JavaScript 事件循环机制的基础。

十四、欢迎交流指正

十五、参考链接

JavaScript——事件循环机制(Event Loop)浅析 - 掘金

https://www.cnblogs.com/kitebear/p/17400025.html

详解:JavaScript事件循环机制(event loop), js运行机制(执行顺序)_javascript 事件循环_陈吖的博客-CSDN博客

web前端tips:js的事件循环(Event Loop)

JavaScript 中 Event Loop 事件循环机制

事件循环机制 (EventLoop)_事件循环原理_星屿H的博客-CSDN博客

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

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

相关文章

coalesce函数(SQL )

用途: 将控制替换成其他值;返回第一个非空值 表达式 COALESCE是一个函数, (expression_1, expression_2, …,expression_n)依次参考各参数表达式,遇到非null值即停止并返回该值。如果所有的表达式都是空值,最终将返…

【计算系统】5分钟了解超算,高性能计算,并行计算,分布式计算,网格计算,集群计算以及云计算的区别

5分钟了解超算,高性能计算,并行计算,分布式计算,网格计算,集群计算以及云计算的区别 1. 超算2. 高性能计算3. 并行计算4. 分布式计算5. 网格计算6. 集群计算7. 云计算小结相关资料 1. 超算 超级计算机(Sup…

11.1~11.2双端口RAM(报错复盘,一些理解(循环,阻塞非阻塞),三目运算符解决使能端)

双端口RAM 分别用于读写数据,同时进行 当读使能端有效时可以读出来数据 当写使能端有效时可以覆写数据 读写并行操作 报错 1.reg必须在always里 这个不能assign,因为reg型不能assign,单端口的那个可以assign是因为其定义为了wire型,就不…

快速入手maven

文章目录 Maven介绍Maven安装和配置基于IDEA的Maven工程创建梳理Maven工程GAVP属性Idea构建Maven JavaSE工程Idea构建Maven JavaEE工程1. 手动创建2. 插件方式创建 Maven工程项目结构说明Maven核心功能依赖和构建管理依赖传递和冲突依赖导入失败场景和解决方案扩展构建管理和插…

Spring Boot 面试题——自动装配

目录 Spring Boot 中的自动装配是指什么?解决了什么问题?Spring Boot 自动装配的流程有哪些?Spring Boot 中实现自动装配的原理是什么?Spring 中的 ConfigurationClassPostProcessor 类有什么作用?Spring Boot 自动装配…

识别flink的反压源头

背景 flink中最常见的问题就是反压,这种情况下我们要正确的识别导致反压的真正的源头,本文就简单看下如何正确识别反压的源头 反压的源头 首先我们必须意识到现实中轻微的反压是没有必要去优化的,因为这种情况下是由于偶尔的流量峰值,Task…

unity 从UI上拖出3D物体,(2D转3D)

效果展示: 2D转3D视频 UI结构 UI组件挂载 UI结构 这个脚本挂载到 3D物体身上 using DG.Tweening; using System.Collections; using System.Collections.Generic; using UnityEngine;public class DragGame : MonoBehaviour {[HideInInspector]public bool isDrag…

Redis之 redis.config配置文件

文章目录 前言一、基本配置1.单位2.包含3.网络配置4.通用5.快照6.安全7.限制8.仅追加模式 二、总体主要介绍总结 前言 行家一出手,就知有没有,让一起学习redis.config配置文件。 一、基本配置 Redis 的配置文件位于 Redis 安装目录下,文件名…

2023李宏毅机器学习HW05样例代码中文注释版

这里只是 2023 李宏毅机器学习 HW05 样例代码的中文注释版的分享,下面的内容绝大部分是样例代码,补充了小部分函数的功能解释,没有做函数功能上的修改,是 Simple baseline 版本。 notebook 代码下载: [EN] [ZH] 文章目录 作业描述…

软件测试/测试开发丨利用ChatGPT 生成自动化测试脚本

点此获取更多相关资料 简介 自动化测试脚本可以模拟用户与应用程序的交互,例如点击按钮、输入数据、导航到不同的页面等等,以验证应用程序的正确性、性能和稳定性。 自动化测试在回归测试、冒烟测试等测试流程中都可以极大地起到节省时间、节省人力的作…

优先队列----数据结构

概念 不知道你玩过英雄联盟吗?英雄联盟里面的防御塔会攻击离自己最近的小兵,但是如果有炮车兵在塔内,防御塔会优先攻击炮车(因为炮车的威胁性更大),只有没有兵线在塔内时,防御塔才会攻击英雄。…

Charles小白新手入门教程

最近系统地重温了下Charles的各种功能,根据小破站上百里老师的讲解,做了一些笔记,对于Charles入门小白,多少会有点帮助, 下面就把分享给大家~ 一、Charles介绍 1、Charles简介 是基于http和https的代理服务器。 2、…

香港服务器不稳定的几种情况

​  近年来,随着互联网的迅猛发展,香港作为一个重要的网络枢纽地区,扮演着连接中国内地和国际网络的重要角色。一些用户表示在使用香港服务器时可能会遇到不稳定的情况,导致访问困难、加载缓慢甚至无法连接。 为什么香港服务器会…

【广州华锐互动】军用飞机VR实战训练系统

随着科技的飞速发展,虚拟现实(VR)技术为军事训练带来了前所未有的机遇。军用飞机VR实战训练系统,正是在这一背景下应运而生的一种创新的训练方法。该系统利用先进的虚拟现实技术,为飞行员提供真实且逼真的模拟飞行环境,使之能够在…

如何将极狐GitLab 漏洞报告导出为 HTML 或 PDF 格式或导出到 Jira

目录 导出为 HTML/PDF 将漏洞信息导出到 Jira 参考资料 极狐GitLab 的漏洞报告功能可以让开发人员在统一的平台上面管理代码,对其进行安全扫描、管理漏洞报告并修复漏洞。但有些团队更喜欢使用类似 Jira 的单独工具来管理他们的安全漏洞。他们也可能需要以易于理…

3.网络之UDP

UDP协议 文章目录 UDP协议1. UDP概述2. UDP报文格式3. UDP传输限制4. UDP校验和4.1 CRC 循环冗余校验算法4.2 md5 校验算法 1. UDP概述 UDP(UserDatagramProtocol)是一个简单的面向消息的传输层协议,尽管UDP提供标头和有效负载的完整性验证&a…

机器学习---支持向量机的初步理解

1. SVM的经典解释 改编自支持向量机解释得很好 |字节大小生物学 (bytesizebio.net) 话说,在遥远的从前,有一只贪玩爱搞破坏的妖怪阿布劫持了善良美丽的女主小美,智勇双全 的男主大壮挺身而出,大壮跟随阿布来到了妖怪的住处&…

unraid 安装并设置 zerotier 内网穿透安装 unraid 局域网内其他设备

Read Original 最近看了以下两个文章,感谢发布的各种精彩文章,让我受益匪浅。OPENWRT 的固件在设置了,【自动允许客户端 NAT】后,可以直接访问局域网其他设备,而我 unraid 部署 zerotier 后,只能访问 unra…

STM32:AHT20温湿度传感器驱动程序开发

注:温湿度传感器AHT20数据手册.pdf http://www.aosong.com/userfiles/files/AHT20%E4%BA%A7%E5%93%81%E8%A7%84%E6%A0%BC%E4%B9%A6(%E4%B8%AD%E6%96%87%E7%89%88)%20B1.pdf 一、分析AHT数据手册文档 (1).准备工作 1.新建工程。配置UART2 2.配置I2C1为I2C标准模式&…

C++笔记之实现多态的所有方法

C笔记之实现多态的所有方法 文章目录 C笔记之实现多态的所有方法1.C中多态是是什么?请用简洁准确的话描述2.虚函数实现多态2.1.虚函数(Virtual Functions)2.2.纯虚函数(Pure Virtual Functions)2.3.虚析构函数&#xf…