JavaScript:事件循环机制(EventLoop)

news2024/11/28 7:31:35

一、理解进程、线程

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

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

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

二、理解单线程、多线程

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

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

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

三、理解渲染线程

渲染线程是指用于渲染图形的计算机进程线程。在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'); // 1

setTimeout(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.coloradmin.cn/o/1168773.html

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

相关文章

【jvm】虚拟机栈之方法返回地址

目录 一、说明二、方法退出三、代码示例四、截图示例 一、说明 1. 存放调用该方法的pc寄存器的值。 2. 一个方法的结束,有两种方式:正常执行完成和出现未处理的异常的非正常退出 3. 无论通过哪种方式退出,在方法退出后都返回到该方法被调用的…

【lvgl】linux开发板搭建环境

前言 本章介绍如何在linux开发板准备好了fb0的情况下移植lvgl。 抓取源码 git clone https://github.com/lvgl/lvgl.git git clone https://github.com/lvgl/lv_drivers.git git clone https://github.com/lvgl/lv_demos.git git clone https://github.com/lvgl/lv_port_lin…

【Docker】手把手教你使用Docker搭建kafka【详细教程】

目录 前提条件 1.安装Zookeeper 1.1运行ZooKeeper容器 2.运行Kafka容器 2.1启动Kafka容器 3.验证 3.1进入Kafka容器 3.2查看容器状态 3.3查看容器日志 3.4重新启动容器 3.5创建测试主题 前提条件 1. 安装Docker: 确保你已经在你的Windows机器上安装了Docker。你可以…

升级智能监控,真香!

随着社会的发展与进步,传统依赖看的监控已经无法满足大众的需求,不够智能、识别不精准,传统监控的弊端也日益显现,智能监控升级迫在眉睫。 升级智能监控,不仅能够促进公共安全,同时也能促进社会文明的发展…

Vue3多页面开发实践

前言: 项目需求,把项目中的一个路由页面单摘出来作为一个新的项目。项目部署到服务器上后,通过一个链接的形式可以直接访问到新项目的页面。 解决方式: 使用Vue多页面方式打包项目 实现步骤: 1、在项目的src目录下&am…

四、二叉树

树是常用的数据存储方式,由于树中存在大量的指针结构,所以树的有关操作相对来说是比较难的。 一、 树的定义 这里用二叉树来举例子 使用结构体的方式实现二叉树: struct BinaryTreeNode {int data;BinartTreeNode* left;BinartTreeNode* right; };使用…

柯桥俄语考级培训,俄语专八如何备考

1.用好真题 真题一共分为:口语表述、听力、词汇语法句法、文学常识、国情、阅读理解、俄汉互译、作文等部分。 第一,要自己动手做真题,然后对答案,看错题错在什么地方,还有哪些知识点是盲区。 第二,分析每…

linux下sqlplus登录oracle显示问号处理办法

问题描述 昨天紧急通过rpm按安装方式给客户装了一台linux的19c数据库,操作系统是CentOs Stream release 9,过程不再回忆了… 今天应用发现sqlplus登入后部分显示问号?,需要处理下 原因分析: 很明显,这就是…

Android ConstraintLayout分组堆叠圆角ShapeableImageView

Android ConstraintLayout分组堆叠圆角ShapeableImageView <?xml version"1.0" encoding"utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:app"…

中文大语言模型汇总

推荐一篇非常棒的github&#xff1a;Awesome-Chinese-LLM 另附语言模型排行榜&#xff1a;FastChat 里面总结了几乎所有目前主流的中文大语言模型。在此记录一下&#xff0c;方便以后慢慢学习。

Adobe Photoshop Elements 2024 v24.0 简体中文版 | 中文直装版

下载&#xff1a; http://dt1.8tupian.net/2/29913a53b500.pg3介绍&#xff1a;Photoshop Elements 2024(简称PSE即PS简化版)是一款定位在数码摄影领域的全新的图像处理软件&#xff0c;该软件包括了专业版的大多数特性&#xff0c;只有少量的简化选项&#xff0c;提供了调整颜…

高速缓存--直接映射

某高速缓存大小 256 字节&#xff0c;直接映射&#xff0c;块大小为 16 字节。定义 L 为数据装载命令&#xff0c;S 为存储&#xff0c;M 为数据修改。若每一数据装载(L)或存储(S)操作可引发最多 1次缓存缺失(miss)&#xff1b;数据修改操作(M)可认为是同一地址上 1 次装载后跟…

【3D图像分割】基于Pytorch的VNet 3D图像分割5(改写数据流篇)

在这篇文章&#xff1a;【3D 图像分割】基于 Pytorch 的 VNet 3D 图像分割2&#xff08;基础数据流篇&#xff09; 的最后&#xff0c;我们提到了&#xff1a; 在采用vent模型进行3d数据的分割训练任务中&#xff0c;输入大小是16*96*96&#xff0c;这个的裁剪是放到Dataset类…

将 UniLinks 与 Flutter 集成(安卓 AppLinks + iOS UniversalLinks)

让我们使用 Flutter Mobile 和 Flutter Web 集成 UniLinks。 一步一步的指导&#xff01; 我是 Pedro Dionsio&#xff0c;是葡萄牙 InspireIT 公司的 Flutter 开发人员&#xff0c;我写这个 UniLinks 教程的座右铭是&#xff1a; Firebase DynamicLinks 已被弃用&#xff0…

cocosCreator微信小游戏 之 分享好友和朋友圈(四)

creator版本&#xff1a; 3.8.0 语言&#xff1a; TypeScript 环境&#xff1a; Mac 简介 微信小游戏的分享分为两种&#xff1a; 被动分享 通过右上角的**…**打开&#xff0c;需要手动设置显示菜单才能分享好友或朋友圈主动分享 调用指定的 wx API接口即可进行分享好友 他…

[2016-2018]phpstudy的exp制作

[2016-2018]phpstudy的exp制作 用python的requests模块进行编写 修改请求数据包进行远程代码执行 import requests import base64 def remove_code_execute():try:url input("请输入要测试的网址:")cmd input("想要执行的命令:")cmd f"system({…

开源 | 30余套STM32单片机、嵌入式Linux、物联网、人工智能项目(开发板+教程+视频)

文末免费领取&#xff01; 30余套综合项目案例 STM32单片机、嵌入式、物联网、人工智能 项目文档源码视频 高校教学、学生毕设、个人项目练手 嵌入式实战项目推荐 15个嵌入式LinuxQt综合应用项目&#xff0c;涉及家居、医疗、农业等多种应用领域&#xff0c;案例中使用了嵌…

【MATLAB源码-第66期】基于麻雀搜索算法(SSA)的栅格路径规划,输出做短路径图和适应度曲线。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 麻雀搜索算法&#xff08;Sparrow Search Algorithm, SSA&#xff09;是一种新颖的元启发式优化算法&#xff0c;它受到麻雀社会行为的启发。这种算法通过模拟麻雀的食物搜索行为和逃避天敌的策略来解决优化问题。SSA通过模拟…

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

效果展示&#xff1a; 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…

数据库存储引擎和锁

存储引擎&#xff1a; mysal当中数据用各种不同的技术存储在文件中&#xff0c;每一种技术都使用不同的存储机制&#xff0c;索引技巧&#xff0c;锁定水平以及最终提供的不同功能和能力&#xff0c;这些就是我们说的存储引擎。 功能&#xff1a; 1、mysql将数据存储在文件系…