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.mzph.cn/news/129221.shtml

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

相关文章

Nginx简介,Nginx搭载负载均衡以及Nginx部署前端项目

目录 一. Nginx简介 Nginx的优点 二. Nginx搭载负载均衡 2.1 Nginx安装 2.1.1 安装依赖 2.1.2 解压nginx安装包 2.1.3 安装nginx 2.1.4 启动nginx服务 2.2 tomcat负载均衡 2.3 Nginx配置 三. Nginx前端部署 一. Nginx简介 NGINX(读作:engi…

气膜场馆的降噪方法

在现代社会,噪音已经成为我们生活中难以避免的问题,而气膜场馆也不例外。传统的气膜场馆常常因其特殊结构而面临噪音扩散和回声问题,影响了人们的体验和活动效果。然而,随着科技的进步,多功能声学综合馆应运而生&#…

vscode开启emmet语法

需要在setting.json中添加配置 首先进入设置,然后点击右上角 Vue项目添加如下配置 "emmet.syntaxProfiles": { "vue-html": "html", "vue": "html" },React项目添加如下配置 "emmet.includeLanguages&quo…

大数据Doris(十五):Doris表的字段类型

文章目录 Doris表的字段类型 一、TINYINT数据类型 二、SMALLINT数据类型 三、INT数据类型

【Web】TCP 和 UCP 的含义和区别

文章目录 一、两者含义二、两者区别 一、两者含义 TCP/IP 协议组为传输层指明了两个协议:TCP 和 UDP,他们都是作为应用程序和网络操作的中介物 TCP (传输控制协议):通过三次握手建立可靠的连接,发送端将数据…

Vue3 如何在<script setup>里设置组件name属性

Vue3 如何在<script setup>里设置组件name属性 文章目录 Vue3 如何在\<script setup>里设置组件name属性一、Vue组件中 name 的用处二、难看但实用的方法三、使用第三方插件支持安装插件插件基本配置插件基本使用 四、Vue官方解决方法4.1 Vue3.3版本之前安装插件插…

物理内存的组织形式

由于物理地址是连续的&#xff0c;页也是连续的&#xff0c;每个页大小也是一样的。因而对于任何一个地址&#xff0c;只要直接除一下每页的大小&#xff0c;很容易直接算出在哪一页。每个页有一个结构 struct page 表示&#xff0c;这个结构也是放在一个数组里面&#xff0c;这…

C#中只能在.NetFramework下使用LINQtoSQL不要在.net 下使用

目录 一、在net7.0下无法实现LINQtoSQL 1.VS上建立数据库连接 2.VS上创建LINQtoSQL 二、在.NetFramework4.8下成功实现LINQtoSQL 1.VS上建立数据库连接 2.VS上创建LINQtoSQL 三、结论 四、理由 本文是个人观点&#xff0c;因为我百般努力在.net7.0下无法实现LINQtoSQL的…

RAR Extractor v11.20(mac解压缩软件)

RAR Extractor是一款专门用于解压RAR格式压缩文件的软件&#xff0c;以下是关于RAR Extractor的详细介绍&#xff1a; 强大的解压功能&#xff1a;RAR Extractor能够解压RAR格式的压缩文件&#xff0c;无论是单一的RAR文件还是RAR文件包&#xff0c;都可以通过RAR Extractor进…

uniapp小程序刮刮乐抽奖

使用canvas画布画出刮刮乐要被刮的图片&#xff0c;使用移动清除画布。 当前代码封装为刮刮乐的组件&#xff1b; vue代码&#xff1a; <template><view class"page" v-if"merchantInfo.cdn_static"><image class"bg" :src&q…

多模块项目的搭建以及Nacos服务的发现与调用

这里写目录标题 多模块项目的搭建父项目的构建子模块的创建父子模块的意义 将注册服务引入到父子模块中创建子模块用于发现服务和调用供调用的服务接口创建调用子模块 测试一些小问题 在前文中我们实现了微服务的注册参考此文&#xff1a; Spring Cloud Alibaba中Nacos的安装&a…

基于RK3568的新能源储能能量管理系统ems

新能源储能能量管理系统&#xff08;EMS&#xff09;是一种基于现代化技术的系统&#xff0c;旨在管理并优化新能源储能设备的能量使用。 该系统通过监测、调度和控制新能源储能设备来确保能源的高效利用和可持续发展。 本文将从不同的角度介绍新能源储能能量管理系统的原理、…

what?腾讯云3年轻量2核4G5M服务器566.6元哪去了?

what&#xff1f;腾讯云3年轻量2核4G5M服务器566.6元哪去了&#xff1f;腾讯云双11优惠活动3年轻量2核4G5M服务器从566.6元涨价到756元三年&#xff0c;3年轻量2核2G4M服务器从366.6元恢复到540元三年&#xff0c;大家抓紧吧&#xff0c;三年轻量已经库存已经不多了&#xff0c…

RHCSA --- 第二天

一、查看IP地址 [rootlocalhost ~] ip ad 对应四张网卡 第一张&#xff1a;环回网卡&#xff08;用于测试&#xff09; 第二张&#xff08;主要&#xff09;&#xff1a;以太网网卡&#xff08;ens160&#xff09; 2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP>…

若依分离版——配置多数据源(mysql和oracle),实现一个方法操作多个数据源

目录 一、若依平台配置 二、编写oracle数据库访问的各类文件 三. 一个方法操作多个数据源 一、若依平台配置 1、在ruoyi-admin的pom.xml添加依赖 <dependency> <groupId>com.oracle</groupId> <artifactId>ojdbc6</artifactId> <version…

ElasticSearch 批量插入漏数据

项目场景&#xff1a; 项目中需要把Mysql数据同步到ElasticSearch中 问题描述 数据传输过程中数据不时出现丢失的情况&#xff0c;偶尔会丢失一部分数据&#xff0c;本地测试也无法复现&#xff0c;后台程序也没有报错&#xff0c;一到正式环境就有问题,很崩溃 这里是批量操…

mysql基于软件包升级

注意&#xff1a;无论是什么升级都是有风险的&#xff0c;升级前都需要做一次全备份。 mysql简单备份和恢复-CSDN博客 本文章以5.7升级为8.0为案例演示。 0、准备 1、安装mysql5.7&#xff0c;5.7版本mysql安装演示mysql-linux归档版安装-CSDN博客 2、在官网下载8.0压缩包M…

MySQL中表的增删改查

目录 一、CRUD 二、新增&#xff08;Create&#xff09; &#xff08;1&#xff09;语法 &#xff08;2&#xff09;单行数据全列插入 &#xff08;3&#xff09;多行数据指定列插入 三、查询&#xff08;Retrieve&#xff09; &#xff08;1&#xff09;语法 …

SortableJS:vuedraggable实现元素拖放排序

文档&#xff1a;https://sortablejs.github.io/Sortable/github&#xff1a;https://github.com/SortableJS/SortableVue2: https://github.com/SortableJS/Vue.DraggableVue3: https://github.com/SortableJS/vue.draggable.nextnpm https://www.npmjs.com/package/vuedragga…