全球即时:前端开发必备:Maps与WeakMaps在DOM节点管理中的妙用
这篇文章讨论了使用Maps和WeakMaps处理DOM节点的优势。Maps和WeakMaps是非常实用的工具,尤其在处理大量DOM节点时,它们发挥着重要作用。
文章作者认为,使用Maps和WeakMaps处理 DOM 节点有以下几个优点。首先,它们可以方便地存储和检索数据。与其他数据结构相比,Maps和 WeakMaps 可以更简洁地组织和查找相关数据。其次,它们可以帮助开发者更好地管理内存。当不再需要某个DOM节点时,WeakMaps可以自动释放与该节点相关的内存,从而提高程序的性能。最后,使用 Maps 和 WeakMaps 可以提高代码的可读性和可维护性。将DOM节点与相关数据关联起来,有助于使代码更清晰易懂。
(资料图片)
下面是正文:
在JavaScript中, 我们经常使用普通的对象来存储键/值数据,它们非常擅长这项工作 - 清晰易读:
const person = { firstName: "Alex", lastName: "MacArthur", isACommunist: false};
但是,当我们开始处理经常被读取、更改和添加属性的较大实体时,更倾向于使用Maps。因为在某些情况下,Map 比对象具有多个优势,特别是性能问题或插入顺序比较重要的情况下。
但最近我特别喜欢使用它们来处理大量的DOM节点。
在阅读Caleb Porzio最近的博客文章时,我想到了这个想法。在这篇文章中,他正在使用由10,000个表行组成的表格,其中一个可以是“active”。为了管理选择不同行时的状态,使用对象作为键/值存储。这是他的一个迭代版本的注释版本。
import { ref, watchEffect } from "vue";let rowStates = {};let activeRow;document.querySelectorAll("tr").forEach((row) => { // Set row state. rowStates[row.id] = ref(false); row.addEventListener("click", () => { // Update row state. if (activeRow) rowStates[activeRow].value = false; activeRow = row.id; rowStates[row.id].value = true; }); watchEffect(() => { // Read row state. if (rowStates[row.id].value) { row.classList.add("active"); } else { row.classList.remove("active"); } });});
它使用一个对象作为大型哈希映射表,因此用于关联值的键必须是字符串,因此需要在每个项目上存在唯一的ID(或其他字符串值)。这带来了一些额外的编程开销,需要在需要时生成和读取这些值。
任何对象都可以作为键相反,使用 Map 可以让我们直接将 HTML 节点作为键。因此,该代码片段最终看起来像这样:
import { ref, watchEffect } from "vue";- let rowStates = {};+ let rowStates = new Map();let activeRow;document.querySelectorAll("tr").forEach((row) => {- rowStates[row.id] = ref(false);+ rowStates.set(row, ref(false)); row.addEventListener("click", () => {- if (activeRow) rowStates[activeRow].value = false;+ if (activeRow) rowStates.get(activeRow).value = false; activeRow = row;- rowStates[row.id].value = true;+ rowStates.get(activeRow).value = true; }); watchEffect(() => {- if (rowStates[row.id].value) {+ if (rowStates.get(row).value) { row.classList.add("active"); } else { row.classList.remove("active"); } });});
这里最明显的好处是我不需要担心每行存在唯一ID。节点引用本身是唯一的,可以作为键。因此,既不需要设置也不需要读取任何属性。这更简单、更具弹性。
读/写操作通常更高效当我们处理更大的数据集时,操作的性能显著提高。甚至在规范中也有说明 - 必须以保持性能的方式构建Map
,以便随着项目数量的增加而增长:
Maps must be implemented using either hash tables or other mechanisms that, on average, provide access times that are sublinear on the number of elements in the collection.
“Sublinear” 的意思是性能不会随着 Map 的大小成比例地下降。因此,即使是大型 Map,性能也应该保持相当迅速。
再次强调,没有必要干扰DOM属性或通过类似字符串的ID执行查找。每个键本身就是一个引用,这意味着我们可以跳过一两个步骤。
我进行了一些基本的性能测试来确认所有这些。首先,按照Caleb的场景,我在页面上生成了10,000个
const table = document.createElement("table");document.body.append(table);const count = 10_000;for (let i = 0; i < count; i++) { const item = document.createElement("tr"); item.id = i; item.textContent = "item"; table.append(item);}
接下来,我设置了一个模板来测量循环遍历所有这些行并将一些相关状态存储在对象或Map
中需要多长时间。我还在for
循环中运行了同样的过程多次,然后确定编写和读取所需的平均时间。
const rows = document.querySelectorAll("tr");const times = [];const testMap = new Map();const testObj = {};for (let i = 0; i < 1000; i++) { const start = performance.now(); rows.forEach((row, index) => { // Test Case #1 // testObj[row.id] = index; // const result = testObj[row.id]; // Test Case #2 // testMap.set(row, index); // const result = testMap.get(row); }); times.push(performance.now() - start);}const average = times.reduce((acc, i) => acc + i, 0) / times.length;console.log(average);
我用不同的行大小运行了这个测试:
请记住,即使是稍微不同的情况,这些结果也可能会有很大的差异,但总体而言,它们通常符合我的预期。在处理相对较少的项目时,Map和对象之间的性能是可比的。但随着项目数量的增加,Map开始拉开差距。性能的次线性变化开始显现。
WeakMaps更有效地管理内存有一个特殊版本的 Map 接口,旨在更好地管理内存 - WeakMap 。它通过保持对其键的“弱”引用来实现这一点,因此,如果这些对象键中的任何一个不再具有其他地方绑定的引用,则它有资格进行垃圾回收。因此,当不再需要该键时,整个条目将自动从WeakMap中删除,从而清除更多内存。它也适用于DOM节点。
为了调整这个,我们将使用 FinalizationRegistry ,它会在你正在观察的引用被垃圾回收时触发回调。我们将从几个列表项开始:
- first
- second
- third
接下来,我们将把这些项目放入WeakMap中,并将item2注册为注册表监视的对象。我们将其删除,每当它被垃圾回收时,回调将被触发,我们将能够看到WeakMap如何发生变化。
但是...垃圾收集是不可预测的,也没有官方的方法来触发它,因此为了测试,我们将定期生成一堆对象并将它们保存在内存中。以下是整个脚本:
(async () => { const listMap = new WeakMap(); // Stick each item in a WeakMap. document.querySelectorAll("li").forEach((node) => { listMap.set(node, node.id); }); const registry = new FinalizationRegistry((heldValue) => { // Garbage collection has happened! console.log("After collection:", heldValue); }); registry.register(document.getElementById("item2"), listMap); console.log("Before collection:", listMap); // Remove node, freeing up reference! document.getElementById("item2").remove(); // Periodically create a bunch o" objects to trigger collection. const objs = []; while (true) { for (let i = 0; i < 100; i++) { objs.push(...new Array(100)); } await new Promise((resolve) => setTimeout(resolve, 10)); }})();
在发生任何事情之前,WeakMap如预期的那样包含三个项。但是在从DOM中删除第二项并进行垃圾收集之后,它看起来有点不同
由于节点引用在DOM中不再存在,整个条目已从 WeakMap 中删除,从而释放了更多的内存。这是一个很 nice 功能,有助于使环境的内存更加整洁。
标签:
相关文章
全球即时:前端开发必备:Maps与WeakMaps在DOM节点管理中的妙用
这篇文章讨论了使用Maps和WeakMaps处理DOM节点的优势。Maps和WeakMaps是非常实用的工具,尤其在处理大量DOM
【天天速看料】杨紫琼刘诗诗海清亮相戛纳红毯具体详细内容是什么
杨紫琼刘诗诗海清亮相戛纳红毯今天的热度非常高,现在也是在热搜榜上了,那么具体的杨紫琼刘诗诗海清亮相戛
湖北交投集团1-4月高速公路建设投资同比增长133%
今年以来,湖北交投集团锚定“双千亿”目标,加速推进项目建设,1-4月,高速公路建设完成投资205 49亿元,
报道:四川宜宾珙县发生4.5级地震 暂未收到人员伤亡和财产损失情况报告
5月22日3时56分,四川宜宾市珙县珙泉镇附近(北纬28 40度,东经104 83度)发生4 5级地震,震源深度8千米。
世界快播:英特科技:公司股票将于5月23日在创业板上市 发行价43.99元/股
英特科技5月21日公告,公司股票将于5月23日在深圳证券交易所创业板上市,本次发行价格43 99元 股。公司是一
天天热点!特斯拉FSD是行业回暖的“催化剂”?L4这次不远了
当下的自动驾驶行业是不是还处于寒冬之中?从海外车企和出行科技公司的表现来看,自动驾驶创业公司依然有很
焦点热门:平凡岁月剧情简介_平凡岁月剧情介绍
1、055-79000主要讲述了一个四世同堂的普通家庭,用爱和亲情紧紧维系,共同经历了30年的风雨。2、李大宝(沙溢)是
当前速读:“出轨后,和老婆过性生活是什么感受?”3个男人说了大实话
点击上方蓝字,关注插座APP什么才是摧毁一段婚姻的致命问题?有人说是缺爱,有人说是无性,但现实生活中,
上海虹桥到浦东机场多久_上海虹桥到浦东机场需要多长时间
1、虹桥火车站乘地铁2号线去浦东机场,要到广兰路站换乘进机场的2号线~~同线,只是要换乘一下。2、虹桥-
中国首个量子计算产业联盟再扩容 成员突破80家
中新网合肥5月21日电(记者张俊)2023中国量子计算产业联盟大会21日在安徽省合肥市召开,会上共有34家企业、
第七届世界智能大会签约98个重点项目 协议总金额约815亿元|即时焦点
新华社天津5月20日电(记者王宁、郭方达)记者从天津市工信局了解到,第七届世界智能大会期间,共有98个重
全球滚动:农业农村部王衍:农村金融主要矛盾的难点在于抵押担保和风险处置
5月20日,2023清华五道口全球金融论坛开幕。农业农村部计划财务司副司长王衍围绕“创新机制推动农业农村普
有多少名观众教学反思不足与改进 有多少名观众教学反思 当前视点
今天来聊聊关于有多少名观众教学反思不足与改进,有多少名观众教学反思的文章,现在就为大家来简单介绍下有
第四届健康产业投融资峰会举行 共话资本助力健康产业创新发展-环球微动态
2023年5月20日,由人民日报健康客户端、中银国际联合主办的第四届健康产业投融资峰会在北京举行。本届峰会
热门文章
热点排行
- 全球即时:前端开发必备:Maps与WeakMaps在DOM节点管理中的妙用
- 【天天速看料】杨紫琼刘诗诗海清亮相戛纳红毯具体详细内容是什么
- 《云襄传》大结局,4个未解之谜,一个没解开 环球观热点
- 湖北交投集团1-4月高速公路建设投资同比增长133%
- 卢伟冰谈小米Civi系列:牵引赛道变革,重新定义新潮流手机
- 怎么和女孩子找聊天话题_怎么跟女孩子找话题聊天
- 洛阳首家肯德基“天使餐厅”有爱亮相
- 报道:四川宜宾珙县发生4.5级地震 暂未收到人员伤亡和财产损失情况报告
- 世界快播:英特科技:公司股票将于5月23日在创业板上市 发行价43.99元/股
- 天天热点!特斯拉FSD是行业回暖的“催化剂”?L4这次不远了