js 中堆、栈、队列+宏任务+微任务+web workers

文章目录

    • js 中堆、栈、队列介绍
    • js中 堆、栈、队列的区别与应用
    • 拓展(宏任务与微任务)
    • Web Workers

js 中堆、栈、队列介绍

  1. 栈(Stack)
    • 概念
      • 栈是一种遵循后进先出(LIFO - Last In First Out)原则的数据结构。就像一摞盘子,最后放上去的盘子最先被拿走。在JavaScript中,函数调用栈就是一个典型的栈结构。当一个函数被调用时,它的执行上下文(包括局部变量、参数等信息)就会被压入栈中,当函数执行完毕后,这个执行上下文就会从栈顶弹出。
    • 应用实例
      • 函数调用栈
        • 例如下面的代码:
    function a() {console.log("Function a is called");b();
    }
    function b() {console.log("Function b is called");
    }
    a();
    
  • a函数被调用时,a的执行上下文被压入栈中。然后a函数内部调用b函数,此时b的执行上下文被压入栈顶。b函数执行完毕后,它的执行上下文从栈顶弹出,接着a函数执行完毕,它的执行上下文也弹出栈。
  • 表达式求值(如四则运算)
  • 考虑一个简单的数学表达式求值器,它可以处理简单的四则运算,例如3 + 4 * 2。可以利用栈来实现运算符优先级的计算。先将数字34压入栈,当遇到运算符*时,从栈顶弹出两个数字进行乘法运算,将结果再压入栈。接着遇到+运算符,再从栈顶弹出两个数字进行加法运算。
  1. 堆(Heap)
    • 概念
      • 堆是一种用于动态分配内存的数据结构,在JavaScript中主要用于存储对象和数组(复杂数据类型)。它是一个无序的内存区域,与栈不同,堆中的内存分配和释放是由垃圾回收机制(Garbage Collection)来管理的。JavaScript的引擎会自动分配和回收堆中的内存,程序员一般不需要手动管理堆内存。
    • 应用实例
      • 对象存储
        • 例如创建一个对象:
let person = {name: "John",age: 30
};
  • 这个person对象就存储在堆中。它的内存空间是在运行时动态分配的,JavaScript引擎会在堆中找到一块足够大的空间来存储这个对象的属性和值。
  • 大型数组存储
  • 当创建一个大型数组,如let largeArray = new Array(1000000);,这个数组也是存储在堆中的。因为栈的空间相对较小,通常用于存储简单数据类型(如基本数据类型的值)和函数调用相关的信息,而像这种大型的数据结构就存储在堆中。
  1. 队列(Queue)
    • 概念
      • 队列是一种遵循先进先出(FIFO - First In First Out)原则的数据结构。就像排队买票,先到的人先买票离开。在JavaScript中,可以用数组来模拟队列的操作。
    • 应用实例
      • 任务队列(事件循环中的任务队列)
        • 在JavaScript的事件循环机制中,有宏任务队列和微任务队列。例如,当浏览器加载页面时,用户触发的事件(如点击事件)会被放入宏任务队列。当执行一个异步操作(如setTimeout),它的回调函数也会被放入宏任务队列。当执行栈为空时,事件循环会从宏任务队列中取出一个任务执行。
        • 例如:
console.log("Script start");
setTimeout(() => {console.log("Timeout callback");
}, 0);
console.log("Script end");
  • 在这里,console.log("Script start")先执行,然后setTimeout的回调函数被放入宏任务队列,接着console.log("Script end")执行。当执行栈为空时,从宏任务队列中取出setTimeout的回调函数执行。
  • 数据缓冲队列
  • 假设你正在开发一个网络应用,从服务器接收数据。数据可能是断断续续地到达的,你可以使用一个队列来缓冲这些数据。当接收到新的数据时,将其放入队列的尾部,当需要处理这些数据时,从队列的头部取出数据进行处理。例如:
let dataQueue = [];
function receiveData(data) {dataQueue.push(data);
}
function processData() {if (dataQueue.length > 0) {let data = dataQueue.shift();// 在这里进行数据处理,比如解析数据等操作console.log("Processing data:", data);}
}

js中 堆、栈、队列的区别与应用

  1. 区别
    • 存储数据类型
      • :主要存储基本数据类型(如numberstringbooleanundefinednull)以及函数调用的执行上下文。这些数据的大小是固定的,并且在编译阶段就可以确定所需的内存空间。例如,一个number类型的数据在栈中占用固定的字节数。
      • :用于存储复杂数据类型,也就是对象(包括普通对象、数组、函数等)。对象的大小不固定,因为其属性的数量和内容可以动态变化。比如一个包含多个属性的对象,其内存占用空间取决于属性的数量和每个属性值的大小。
      • 队列:本身不用于存储特定的数据类型,而是一种数据结构模式。在JavaScript实现中,通常可以用数组来存储各种类型的数据,无论是基本数据类型还是对象,重点在于按照先进先出的规则操作这些数据。
    • 内存管理方式
      • :内存的分配和释放是自动的,遵循后进先出原则。当一个函数被调用时,其相关的局部变量等信息被压入栈,函数执行结束后,这些信息就会从栈顶自动弹出,内存空间被释放。这种自动管理机制简单高效,但栈的空间相对较小。
      • :内存的分配是动态的,由JavaScript引擎的垃圾回收机制(Garbage Collection,GC)来管理。当对象不再被引用时,垃圾回收器会在适当的时候回收其占用的内存。由于堆的内存空间较大,但管理相对复杂,垃圾回收过程可能会对性能产生一定影响。
      • 队列:在内存管理方面没有特殊的机制,主要依赖于所使用的存储结构(如数组)自身的内存管理。如果用数组来模拟队列,数组的内存分配和释放遵循JavaScript中数组的规则。
    • 数据访问方式
      • :数据的访问遵循后进先出原则,只能从栈顶进行插入(压栈)和删除(出栈)操作。就像一个只有一个开口的容器,最后放入的东西最先被取出。
      • :对象在堆中的存储位置是通过引用(指针)来访问的。一个变量(存储在栈中)保存了对象在堆中的内存地址,通过这个引用可以访问和操作对象的属性。访问对象的属性是通过解引用的方式,从存储引用的变量找到堆中的对象。
      • 队列:按照先进先出的规则访问数据,从队列头部取出数据,从队列尾部插入数据。可以将其想象成一个管道,数据从一端进入,从另一端出去。
  2. 应用
  • 栈的应用
    - 函数调用和递归:在函数调用过程中,栈用于存储函数的执行上下文,包括局部变量、参数、返回地址等信息。递归函数的执行也依赖于栈,每一次递归调用都会将新的执行上下文压入栈中。例如,计算阶乘的递归函数:
function factorial(n) {if (n === 0 || n === 1) {return 1;}return n * factorial(n - 1);
}
  • 表达式求值:可以利用栈来实现算术表达式求值,特别是对于包含括号和不同优先级运算符的表达式。例如,将中缀表达式转换为后缀表达式并求值的过程中,栈可以用于存储运算符和操作数,按照运算符的优先级和括号规则进行计算。
  • 堆的应用
    • 对象和数组操作:在JavaScript中,几乎所有的对象和数组都存储在堆中。这包括创建和操作DOM节点(在浏览器环境中)、处理复杂的数据结构如树形结构(如HTML文档的DOM树)、存储和管理大量的数据集合(如数据库查询结果以对象数组形式存储)。
      • 动态内存分配:当需要在运行时动态创建大量的数据结构,如游戏中的角色属性对象、图形绘制中的图形对象等,这些对象的内存分配都在堆中进行。垃圾回收机制确保了在对象不再使用时释放内存,防止内存泄漏。
    • 队列的应用
      • 任务队列和事件循环:在JavaScript的事件驱动编程模型中,任务队列(宏任务队列和微任务队列)是核心概念。例如,setTimeoutsetInterval的回调函数、用户触发的事件处理函数(如点击事件、键盘事件等)都被放入任务队列中,等待执行栈空闲后按照先进先出的顺序执行。
      • 消息队列和异步处理:在一些异步编程场景中,如Web Workers(在浏览器中实现后台线程处理)或者Node.js中的异步I/O操作,消息队列可以用于传递和处理异步任务的结果。比如,一个Web Worker完成计算任务后,将结果通过消息队列发送回主线程进行处理。

拓展(宏任务与微任务)

  1. 概念
    • 宏任务队列(Macrotask Queue)
      • 宏任务队列是一个用于存储宏任务的队列。宏任务是指那些比较大型、执行时间相对较长的任务。在浏览器环境或者Node.js环境中,常见的宏任务包括setTimeoutsetIntervalI/O操作(如读取文件、网络请求)、DOM操作(如添加或删除节点)等。这些任务按照先进先出(FIFO)的原则排队等待执行。
      • 事件循环(Event Loop)会不断检查调用栈是否为空,当调用栈为空时,它会从宏任务队列中取出一个宏任务放入调用栈中执行。例如,当设置一个setTimeout函数时,其回调函数就会被放入宏任务队列中,等待合适的时机执行。
    • 微任务队列(Microtask Queue)
      • 微任务队列用于存储微任务。微任务通常是一些比较小的、执行速度相对较快的任务。在JavaScript中,常见的微任务包括Promisethen/catch/finally回调、MutationObserver(用于观察DOM变化)回调、queueMicrotask函数(用于手动添加微任务)等。
      • 微任务队列的优先级高于宏任务队列。当一个宏任务执行完毕后,在执行下一个宏任务之前,事件循环会先检查微任务队列是否为空。如果微任务队列中有任务,就会依次执行这些微任务,直到微任务队列清空后,才会从宏任务队列中取出下一个宏任务执行。
  2. 工作流程示例
    • 假设我们有以下代码:
console.log('Script start');
setTimeout(() => {console.log('SetTimeout callback');
}, 0);
Promise.resolve().then(() => {console.log('Promise then callback');
});
console.log('Script end');
  • 执行过程如下:
    • 首先执行console.log('Script start'),输出Script start
    • 遇到setTimeout,其回调函数被放入宏任务队列。
    • 遇到Promise.resolve().then(),其回调函数被放入微任务队列。
    • 执行console.log('Script end'),输出Script end
    • 此时当前宏任务(主代码块)执行完毕,事件循环检查微任务队列,发现有任务,执行Promisethen回调函数,输出Promise then callback
    • 微任务队列清空后,事件循环从宏任务队列中取出setTimeout的回调函数并执行,输出SetTimeout callback
  1. 应用场景
    • 微任务队列应用场景
      • 异步操作的顺序保证Promise广泛用于处理异步操作,通过微任务队列可以确保Promise的后续操作(thencatchfinally)按照正确的顺序执行。例如,在一系列连续的Promise操作中,后一个Promisethen回调可以在前一个Promise完成后立即执行,保证了异步操作的连贯性。
      • DOM更新的优化MutationObserver利用微任务队列来处理DOM的变化观察。当DOM发生变化时,MutationObserver的回调函数作为微任务执行。这使得DOM更新可以在当前宏任务执行完所有同步操作之后、下一个宏任务开始之前进行处理,避免了不必要的DOM重绘和回流,提高了性能。
    • 宏任务队列应用场景
      • 延迟执行和定时任务setTimeoutsetInterval是典型的宏任务应用,用于在指定的延迟时间后执行任务或者周期性地执行任务。例如,在网页中实现一个定时刷新数据的功能,或者在一定延迟后显示一个提示信息,都可以使用setTimeout将相应的任务放入宏任务队列。
      • I/O操作和长时间任务:在Node.js中,读取文件、网络请求等I/O操作通常作为宏任务。这些任务可能需要较长的时间来完成,将它们放入宏任务队列可以让其他任务(如处理用户输入、执行一些快速的计算等)在等待I/O完成的过程中继续执行,提高系统的整体效率。

Web Workers

  1. Web Workers概念

    • Web Workers是HTML5提供的一种在后台线程中运行脚本的机制。在传统的JavaScript编程中,所有的脚本都在单线程(主线程)中运行,这意味着如果一个任务需要花费很长时间,如复杂的计算或者大量的数据处理,会阻塞主线程,导致页面无响应(例如,浏览器的UI冻结,用户无法进行交互操作)。Web Workers允许你将一些耗时的任务放在独立于主线程的后台线程中执行,这样主线程可以继续响应用户的操作,从而提高页面的性能和用户体验。
    • Web Workers通过消息传递机制与主线程进行通信。它不能直接访问DOM元素,因为DOM操作不是线程安全的,多个线程同时操作DOM可能会导致不可预测的错误。每个Web Worker都有自己的全局对象(self),这个全局对象与主线程的window对象不同,它没有documentwindow等与DOM相关的属性。
  2. 应用场景

    • 复杂计算任务
      • 在一些需要进行大量数学计算的场景中,如数据加密/解密、图形渲染中的数学计算(例如3D图形的光线追踪算法)、金融数据计算(如风险评估模型)等。这些计算可能会花费大量时间,如果在主线程中进行,会导致页面卡顿。使用Web Workers可以将这些计算任务放在后台线程进行,不影响主线程的正常运行。
    • 数据处理任务
      • 当需要处理大量的数据,如大数据集的排序、过滤、分析等。例如,在一个数据分析Web应用中,用户上传一个包含大量数据点的文件,需要对这些数据进行统计分析。可以使用Web Workers在后台处理这些数据,同时主线程可以更新进度条或者响应用户的其他操作。
    • 多任务并发处理
      • 对于一些可以并行处理的任务,比如同时从多个不同的服务器获取数据(如多图加载)或者同时进行多个独立的计算任务。通过创建多个Web Workers,可以并发地处理这些任务,加快整体任务的完成速度。
  3. 实例

    • 计算斐波那契数列(复杂计算任务)
      • 主线程代码(index.html):
<!DOCTYPE html>
<html>
<head><title>Web Workers Fibonacci Example</title>
</head>
<body><p>计算斐波那契数列</p><input type="number" id="inputNumber" placeholder="输入斐波那契数列的项数"><button id="calculateButton">计算</button><div id="result"></div><script>const calculateButton = document.getElementById('calculateButton');const resultDiv = document.getElementById('result');const inputNumber = document.getElementById('inputNumber');calculateButton.addEventListener('click', function () {const worker = new Worker('worker.js');const n = parseInt(inputNumber.value);worker.addEventListener('message', function (event) {resultDiv.textContent = '斐波那契数列的第' + n +'项是:' + event.data;});worker.postMessage(n);});</script>
</body>
</html>
  • Web Worker代码(worker.js):
self.addEventListener('message', function (e) {const n = e.data;function fibonacci(n) {if (n === 0 || n === 1) {return n;}let a = 0, b = 1, temp;for (let i = 2; i <= n; i++) {temp = a + b;a = b;b = temp;}return b;}self.postMessage(fibonacci(n));
});
  • 在这个例子中,当用户点击“计算”按钮时,主线程创建一个Web Worker,并将用户输入的斐波那契数列的项数发送给Web Worker。Web Worker在后台线程中计算斐波那契数列的指定项,计算完成后将结果发送回主线程。主线程收到结果后,将其显示在页面上。整个计算过程不会阻塞主线程,用户可以在计算过程中继续与页面进行交互。

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

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

相关文章

java面向对象编程特性概述

目录 1. 类和对象 2. 封装&#xff08;Encapsulation&#xff09; 3. 继承&#xff08;Inheritance&#xff09; 4. 多态&#xff08;Polymorphism&#xff09; 5. 抽象&#xff08;Abstraction&#xff09; (1). 抽象类&#xff08;Abstract Class&#xff09; (2).接口…

React(二)——Admin主页/Orders页面/Category页面

文章目录 项目地址一、侧边栏1.1 具体实现 二、Header2.1 实现 三、Orders页面3.1 分页和搜索3.2 点击箭头显示商家所有订单3.3 页码按钮以及分页 四、Category页面4.1 左侧商品添加栏目4.2 右侧商品上传栏 五、Sellers页面六、Payment Request 页面&#xff08;百万数据加载&a…

maven 下载依赖 jhash:2.1.2 和对应 jar 包

原文地址 前言 25年新的一年&#xff0c;那就先更新一篇技术文章吧&#xff0c;这个是这几天刚遇到的一个有意思的bug&#xff0c;记录分享一下 原因分析 在使用maven加载一个项目的时&#xff0c;发现maven的依赖一直无法解析&#xff0c;更换阿里云镜像和中央仓库都没办法…

nums[:]数组切片

问题&#xff1a;给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数。 使用代码如下没有办法通过测试示例&#xff0c;必须将最后一行代码改成 nums[:]nums[-k:]nums[:-k]切片形式&#xff1a; 原因&#xff1a;列表的切片操作 …

python-leetcode-三数之和

15. 三数之和 - 力扣&#xff08;LeetCode&#xff09; class Solution:def threeSum(self, nums: List[int]) -> List[List[int]]:nums.sort() # 排序n len(nums)res []for i in range(n):# 剪枝&#xff1a;如果当前数 > 0&#xff0c;三数之和不可能为 0if nums[i]…

极狐GitLab 正式发布安全版本17.7.1、17.6.3、17.5.5

本分分享极狐GitLab 补丁版本 17.7.1, 17.6.3, 17.5.5 的详细内容。这几个版本包含重要的缺陷和安全修复代码&#xff0c;我们强烈建议所有私有化部署用户应该立即升级到上述的某一个版本。对于极狐GitLab SaaS&#xff0c;技术团队已经进行了升级&#xff0c;无需用户采取任何…

探索绿色能源系统的固态继电器:2025年展望

随着全球向绿色能源转型的加速&#xff0c;对高效、可靠和环保元件的需求从未如此强烈。在这种背景下&#xff0c;国产固态继电器(SSR)在实现太阳能逆变器、风力涡轮机和储能系统等关键技术方面发挥着关键作用。本文探讨了绿色能源系统背景下中国固态继电器行业的前景&#xff…

Rust语言使用iced实现简单GUI页面

使用cargo新建一个rust项目 cargo new gui_demo cd gui_demo 编辑Cargo.toml文件 ,添加iced依赖 [package] name "gui_demo" version "0.1.0" edition "2021"[dependencies] iced "0.4.2" 编辑src/main.rs文件&#xff1a; u…

Github提交Pull Request教程 Git基础扫盲(零基础易懂)

1 PR是什么&#xff1f; PR&#xff0c;全称Pull Request&#xff08;拉取请求&#xff09;&#xff0c;是一种非常重要的协作机制&#xff0c;它是 Git 和 GitHub 等代码托管平台中常见的功能&#xff0c;被广泛用于参与社区贡献&#xff0c;从而促进项目的发展。 PR的整个过…

RabbitMQ 可观测性最佳实践

RabbitMQ 简介 RabbitMQ 是一个开源的消息代理和队列服务器&#xff0c;用 Erlang 语言编写&#xff0c;支持多种客户端。它通过使用交换机&#xff08;Exchanges&#xff09;、队列&#xff08;Queues&#xff09;和绑定&#xff08;Bindings&#xff09;来路由消息&#xff…

美摄科技PC端视频编辑解决方案,为企业打造专属的高效创作平台

在当今这个信息爆炸的时代&#xff0c;视频已成为不可或缺的重要内容形式&#xff0c;美摄科技推出了PC端视频编辑解决方案的私有化部署服务&#xff0c;旨在为企业提供一款量身定制的高效创作平台。 一、全面功能&#xff0c;满足企业多样化需求 美摄科技的PC端视频编辑解决…

【Oracle篇】深入了解执行计划中的访问路径(含表级别、B树索引、位图索引、簇表四大类访问路径)

&#x1f4ab;《博主介绍》&#xff1a;✨又是一天没白过&#xff0c;我是奈斯&#xff0c;从事IT领域✨ &#x1f4ab;《擅长领域》&#xff1a;✌️擅长阿里云AnalyticDB for MySQL(分布式数据仓库)、Oracle、MySQL、Linux、prometheus监控&#xff1b;并对SQLserver、NoSQL(…

腾讯云AI代码助手编程挑战赛-厨房助手之AI大厨

腾讯云AI代码助手编程挑战赛-厨房助手之AI大厨 作品简介 身处当今如火箭般迅猛发展的互联网时代&#xff0c;智能聊天助手已然化身成为提升用户体验的关键利器&#xff0c;全方位渗透至人们的数字生活。 紧紧跟随着这股汹涌澎湃的时代浪潮&#xff0c;我毅然投身于极具挑战性…

vscode 无法使用npm, cmd命令行窗口可以正常执行

解决方法&#xff1a; 执行命令获得命令的位置 get-command npm 得到如下 然后删除或者修改 npm.ps1文件 让其不能使用就行。然后重启vscode即可。 pnpm 同理即可 另外加速源 国内镜像源&#xff08;淘宝&#xff09;&#xff1a; npm config set registry https://regist…

简易CPU设计入门:算术逻辑单元(四)

项目代码下载 请大家首先准备好本项目所用的源代码。如果已经下载了&#xff0c;那就不用重复下载了。如果还没有下载&#xff0c;那么&#xff0c;请大家点击下方链接&#xff0c;来了解下载本项目的CPU源代码的方法。 CSDN文章&#xff1a;下载本项目代码 上述链接为本项目…

Spring Boot 和微服务:快速入门指南

&#x1f496; 欢迎来到我的博客&#xff01; 非常高兴能在这里与您相遇。在这里&#xff0c;您不仅能获得有趣的技术分享&#xff0c;还能感受到轻松愉快的氛围。无论您是编程新手&#xff0c;还是资深开发者&#xff0c;都能在这里找到属于您的知识宝藏&#xff0c;学习和成长…

VSCode 使用鼠标滚轮控制字体

一、 文件 | 首选项 | 设置 二、单击在 settings.json中编辑 "editor.mouseWheelZoom": true 注注注意&#xff1a;保存哦&#xff01;ctrlS 三、测试 按住ctrl鼠标滚轮&#xff0c;控制字体大小

rabbitmq的三个交换机及简单使用

提前说一下&#xff0c;创建队列&#xff0c;交换机&#xff0c;绑定交换机和队列都是在生产者。消费者只负责监听就行了&#xff0c;不用配其他的。 完成这个场景需要两个服务哦。 1直连交换机-生产者的代码。 在配置类中创建队列&#xff0c;交换机&#xff0c;绑定交换机…

代码随想录算法训练营第3天(链表1)| 203.移除链表元素 707.设计链表 206.反转链表

一、203.移除链表元素 题目&#xff1a;203. 移除链表元素 - 力扣&#xff08;LeetCode&#xff09; 视频&#xff1a;手把手带你学会操作链表 | LeetCode&#xff1a;203.移除链表元素_哔哩哔哩_bilibili 讲解&#xff1a;代码随想录 注意&#xff1a; 针对头结点和非头结点的…

CES Asia 2025科技盛宴,AI智能体成焦点

2025第七届亚洲消费电子技术展&#xff08;CES Asia赛逸展&#xff09;将在北京拉开帷幕&#xff0c;AI智能体有望成为展会的核心亮点。 深圳市人工智能行业协会发文表示全力支持CES Asia 2025&#xff08;赛逸展&#xff09;&#xff0c;称其为人工智能领域的创新发展提供了强…