品牌 资讯 搭配 材料 时尚 热点 行业 首饰 玉石 行情

全球即时:前端开发必备:Maps与WeakMaps在DOM节点管理中的妙用

2023-05-22 12:29:52 来源:大迁世界

这篇文章讨论了使用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

2023-05-22 12:29:52

【天天速看料】杨紫琼刘诗诗海清亮相戛纳红毯具体详细内容是什么

​杨紫琼刘诗诗海清亮相戛纳红毯今天的热度非常高,现在也是在热搜榜上了,那么具体的杨紫琼刘诗诗海清亮相戛

2023-05-22 11:56:05

《云襄传》大结局,4个未解之谜,一个没解开 环球观热点

​《云襄传》大结局,4个未解之谜,一个没解开,福王,玉佩,南宫,莲衣,云襄传

2023-05-22 11:20:26

湖北交投集团1-4月高速公路建设投资同比增长133%

​今年以来,湖北交投集团锚定“双千亿”目标,加速推进项目建设,1-4月,高速公路建设完成投资205 49亿元,

2023-05-22 10:53:10

卢伟冰谈小米Civi系列:牵引赛道变革,重新定义新潮流手机

​千易网5月22日消息,小米今日宣布小米Civi3定档5月25日正式发布。Redmi品牌总经理卢伟

2023-05-22 10:17:13

怎么和女孩子找聊天话题_怎么跟女孩子找话题聊天

​1、第一点:建立沟通朋友圈,这个很重要,要根据朋友圈,大致判断出对方是个什么样的人,做好预估。2、从对

2023-05-22 09:44:46

洛阳首家肯德基“天使餐厅”有爱亮相

​“天使员工”为顾客点餐(图片由肯德基提供)昨天是第33次全国助残日。日前,洛阳首家肯德基“天使餐厅”—

2023-05-22 09:24:02

报道:四川宜宾珙县发生4.5级地震 暂未收到人员伤亡和财产损失情况报告

​5月22日3时56分,四川宜宾市珙县珙泉镇附近(北纬28 40度,东经104 83度)发生4 5级地震,震源深度8千米。

2023-05-22 08:51:49

世界快播:英特科技:公司股票将于5月23日在创业板上市 发行价43.99元/股

​英特科技5月21日公告,公司股票将于5月23日在深圳证券交易所创业板上市,本次发行价格43 99元 股。公司是一

2023-05-22 08:00:58

天天热点!特斯拉FSD是行业回暖的“催化剂”?L4这次不远了

​当下的自动驾驶行业是不是还处于寒冬之中?从海外车企和出行科技公司的表现来看,自动驾驶创业公司依然有很

2023-05-22 06:55:41

平安i贷网贷逾期4天延迟还款会上征信系统吗 环球新视野

​网贷逾期一般会上征信,有些借贷机构在用户逾期后一天后就会上报给征信机构,而有些借贷机构则是会在几天后

2023-05-22 06:00:01

焦点热门:平凡岁月剧情简介_平凡岁月剧情介绍

​1、055-79000主要讲述了一个四世同堂的普通家庭,用爱和亲情紧紧维系,共同经历了30年的风雨。2、李大宝(沙溢)是

2023-05-22 03:47:44

当前速读:“出轨后,和老婆过性生活是什么感受?”3个男人说了大实话

​点击上方蓝字,关注插座APP什么才是摧毁一段婚姻的致命问题?有人说是缺爱,有人说是无性,但现实生活中,

2023-05-22 00:08:34

游客登大珠山崴脚骨折,警民合力抬下山 环球播资讯

​5月20日,青岛西海岸新区一名游客在大珠山景区登山时,不慎崴脚导致骨折,黄岛警方接到求助后,民警会同消

2023-05-21 22:00:35

国轩高科发布启晨L600电池

​5月19日上午,国轩高科第十二届科技大会在合肥开幕,公司同时发布了最新自研LMFP体系的L600启晨电芯及电池

2023-05-21 20:48:46

上海虹桥到浦东机场多久_上海虹桥到浦东机场需要多长时间

​1、虹桥火车站乘地铁2号线去浦东机场,要到广兰路站换乘进机场的2号线~~同线,只是要换乘一下。2、虹桥-

2023-05-21 19:46:38

中国首个量子计算产业联盟再扩容 成员突破80家

​中新网合肥5月21日电(记者张俊)2023中国量子计算产业联盟大会21日在安徽省合肥市召开,会上共有34家企业、

2023-05-21 18:50:20

环球通讯!我市80余款茶产品亮相茶博会

​点击上方 "汉中视听 "  关注我们吧    世界好茶聚杭州,钱江两岸闻茶香。5月20日上午,由农业农村部

2023-05-21 17:46:40

今年夏收夏种期间 大部分时段天气条件总体较好 环球快播报

​今天(5月21日)迎来小满节气,这是夏季的第二个节气,也是夏季节气中升温速度最快的。

2023-05-21 16:34:07

才貌双全!来自浙江的清华大学女生获选美冠军

​近日第72届世界小姐选美大赛传来消息来自浙江的清华大学女生洪昊昀获得中国区最强人气冠军和东部赛区冠军决

2023-05-21 15:54:21

无花果树喜阴还是喜阳 无花果树喜阴凉还是喜阳光的呢

​1、无花果是喜阳的植物,有光照充足的环境,无花果才长的快、壮实、结果多、甜度高。如果无花果树没有阳光

2023-05-21 14:37:37

第七届世界智能大会签约98个重点项目 协议总金额约815亿元|即时焦点

​新华社天津5月20日电(记者王宁、郭方达)记者从天津市工信局了解到,第七届世界智能大会期间,共有98个重

2023-05-21 13:41:04

国家节水型城市已建成145个

​5月14日至20日是2023年全国城市节约用水宣传周,主题为“推进城市节水,建设宜居城市”。记者近日从住房和

2023-05-21 12:04:20

全球滚动:农业农村部王衍:农村金融主要矛盾的难点在于抵押担保和风险处置

​5月20日,2023清华五道口全球金融论坛开幕。农业农村部计划财务司副司长王衍围绕“创新机制推动农业农村普

2023-05-21 10:56:12

快消息!趟过女人河的男人电视剧全集_趟过女人河

​1、是由陈中庆著作,2004年李琳、刘家良主演的爱情文艺电视剧。讲述的是有情有义的男主,在风风雨雨的坎坷

2023-05-21 09:59:37

有多少名观众教学反思不足与改进 有多少名观众教学反思 当前视点

​今天来聊聊关于有多少名观众教学反思不足与改进,有多少名观众教学反思的文章,现在就为大家来简单介绍下有

2023-05-21 09:05:20

如何呵护“铁脚板”

​脚部位于人体最底端,要承受全身重量。

2023-05-21 08:11:41

苏丹冲突双方达成为期7天的停火协议

​当地时间20日,苏丹武装部队和苏丹快速支援部队在沙特吉达签署了为期7天的停火协议。协议自签署48小时后开

2023-05-21 06:53:48

第四届健康产业投融资峰会举行 共话资本助力健康产业创新发展-环球微动态

​2023年5月20日,由人民日报健康客户端、中银国际联合主办的第四届健康产业投融资峰会在北京举行。本届峰会

2023-05-21 05:48:20

环球快讯:定向共晶性高温合金

​1、定向共晶性高温合金是在控制定向凝固条件下形成共晶成分的高温合金。2、常将两种或两种以上的金属元素或

2023-05-21 03:01:46