广告
返回顶部
首页 > 资讯 > 精选 >Vue3中怎么用WeakMap作为缓存区
  • 546
分享到

Vue3中怎么用WeakMap作为缓存区

2023-06-22 04:06:54 546人浏览 泡泡鱼
摘要

这篇文章主要介绍“vue3中怎么用WeakMap作为缓存区”,在日常操作中,相信很多人在Vue3中怎么用WeakMap作为缓存区问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Vue3中怎么用WeakMap作为

这篇文章主要介绍“vue3中怎么用WeakMap作为缓存区”,在日常操作中,相信很多人在Vue3中怎么用WeakMap作为缓存区问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Vue3中怎么用WeakMap作为缓存区”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

Vue3中怎么用WeakMap作为缓存区

在读 Vue 3  响应式原理部分代码的过程中看到其在进行响应式处理的时候,为每个对象使用 WeakMap 创建了一个「缓存区」,代码如下:

// 注意下面这句代码!const ReactiveMap = new WeakMap();// 核心进行劫持的方法  处理 get 和 set 的逻辑const mutableHandlers = {    get,    set}function reactive(target: object) {    return createReactiveObject(target, mutableHandlers, reactiveMap);}function createReactiveObject(target, baseHandlers, proxyMap) {    // 检测 target 是不是对象,不是对象直接返回,不进行代理    if (!isObject(target)) {        return target    }    const existsProxy = proxyMap.get(target);    // 如果该对象已经被代理过了,则直接返回,不进行重复代理    if (existsProxy) {        return existsProxy    }    // 未被代理过,则创建代理对象    const proxy = new Proxy(target,baseHandlers);    // 缓存,避免重复代理,即避免 reactive(reactive(Object)) 的情况出现    proxyMap.set(target,proxy);     return proxy}

从上面的代码可以看出,WeakMap 缓存区的作用就是用来防止对象被重复代理。

为什么 Vue 3 使用 WeakMap 来缓存代理对象?为什么不使用其他的方式来进行缓存,比如说 Map

什么是 WeakMap

WeakMap 对象是一组键值对的集合,其中的键是 弱引用 的。其键必须是 对象,而值可以是任意的。

语法

new WeakMap([iterable])

Iterable 是一个数组(二元数组)或者其他可迭代的且其元素是键值对的对象。每个键值对会被加到新的 WeakMap 里。

方法

WeakMap 有四个方法:分别是 getsethasdelete,下面我们看一下其大致的用法:

const wm1 = new WeakMap(),      wm2 = new WeakMap(),      wm3 = new WeakMap();const o1 = {},      o2 = function() {},      o3 = window;wm1.set(o1, 37);wm1.set(o2, "azerty");wm2.set(o1, o2); // value 可以是任意值,包括一个对象或一个函数wm2.set(o3, undefined);wm2.set(wm1, wm2); // 键和值可以是任意对象,甚至另外一个 WeakMap 对象wm1.get(o2); // "azerty"wm2.get(o2); // undefined,wm2 中没有 o2 这个键wm2.get(o3); // undefined,值就是 undefinedwm1.has(o2); // truewm2.has(o2); // falsewm2.has(o3); // true (即使值是 undefined)wm3.set(o1, 37);wm3.get(o1); // 37wm1.has(o1);   // truewm1.delete(o1);wm1.has(o1);   // false

为什么要用 WeakMap 而不是 Map

javascript 里,map api 可以通过四个 API 方法共用两个数组(一个存放键,一个存放值)来实现。这样在给这种 map 设置值时会同时将键和值添加到这两个数组的末尾。从而使得键和值的索引在两个数组中相对应。当从该 map 取值的时候,需要遍历所有的键,然后使用索引从存储值的数组中检索出相应的值。

但这样的实现会有两个很大的缺点,首先赋值和搜索操作都是 O(n) 的时间复杂度(n 是键值对的个数),因为这两个操作都需要遍历整个数组来进行匹配。

另外一个缺点是可能会导致 内存泄漏,因为数组会一直引用着每个键和值。这种引用使得 垃圾回收算法不能回收处理他们,即使没有其他任何引用存在了。

let jser = { name: "dachui" };let array = [ jser ];jser = null; // 覆盖引用

上面这段代码,我们把一个对象放入到数组中,那么只要这个数组存在,那么这个对象也就存在,即使没有其他对该对象的引用

let jser = { name: "dachui" };let map = new Map();map.set(jser, "");jser = null; // 覆盖引用

类似的,如果我们使用对象作为常规 Map 的键,那么当 Map 存在时,该对象也将存在。它会占用内存,并且不会被垃圾回收机制回收。

相比之下,原生的 WeakMap 持有的是每个键对象的 弱引用,这意味着在没有其他引用存在时垃圾回收能正确进行。

正是由于这样的弱引用,WeakMapkey 是不可枚举的 (没有方法能给出所有的 key)。如果 key 是可枚举的话,其列表将会受垃圾回收机制的影响,从而得到不确定的结果。因此,如果你想要这种类型对象的 key 值的列表,你应该使用 Map

综上,我们可以得出以下结论:WeakMap 的键所指向的对象,不计入垃圾回收机制

所以,如果你要往对象上添加数据,又不想干扰垃圾回收机制,就可以使用 WeakMap

看到这里大家就应该知道了,Vue 3 之所以使用 WeakMap 来作为缓冲区就是为了能将 不再使用的数据进行正确的垃圾回收

什么是弱引用

关于「弱引用」,维基百科给出了答案:

在计算机程序设计中,弱引用强引用 相对,是指不能确保其引用的对象不会被垃圾回收器回收的引用。一个对象若只被弱引用所引用,则被认为是不可访问(或弱可访问)的,并因此 可能在任何时刻被回收

为什么会出现弱引用

那么,为什么会出现弱引用呢?弱引用除了能解决上述问题之外还能解决什么问题呢?要想回答这些问题,我们首先需要了解一下 V8 引擎是如何进行垃圾回收的。

对于 JSer 来说,内存的管理是自动的、无形的,这一切都归功于 V8 引擎在背后默默地帮我们找到不需要使用的内存并进行清理。

那么,当我们不再需要某个东西时会发生什么,V8 引擎又是如何发现并清理它的呢?

现在各大浏览器通常用采用的垃圾回收有两种方法,一种是「引用计数」,另外一种就是「标记清除」。下面我们来看一下:

标记清除

标记清除被称为 mark-and-sweep,它是基于 可达性 来判断对象是否存活的,它会定期执行以下「垃圾回收」步骤:

  • 垃圾收集器找到所有的根,并标记(记住)它们。

  • 然后它遍历并标记来自它们的所有引用。所有被遍历到的对象都会被记住,以免将来再次遍历到同一个对象。

  • ……如此操作,直到所有可达的(从根部)引用都被访问到。

  • 没有被标记的对象都会被删除。

我们还可以将这个过程想象成从根溢出一个巨大的油漆桶,它流经所有引用并标记所有可到达的对象,然后移除未标记的。

引用计数

引用计数方式最基本的形态就是让每个被管理的对象与一个引用计数器关联在一起,该计数器记录着该对象当前被引用的次数,每当创建一个新的引用指向该对象时其计数器就加 1,每当指向该对象的引用失效时计数器就减 1。当该计数器的值降到 0 就认为对象死亡。

区别

引用计数与基于「可达性」的标记清除的内存管理方式最大的区别就是,前者只需要 局部的信息,而后者需要 全局的信息

在引用计数中每个计数器只记录了其对应对象的局部信息 —— 被引用的次数,而没有(也不需要)一份全局的对象图的生死信息。

由于只维护局部信息,所以不需要扫描全局对象图就可以识别并释放死对象。但也因为缺乏全局对象图信息,所以 无法处理循环引用 的状况。

所以,更高级的引用计数实现会引入 弱引用 的概念来打破某些已知的循环引用。

WeakMap 应用

存储 DOM 节点

WeakMap 应用的典型场合就是以 DOM 节点作为键名。下面是一个例子。

const myWeakmap = newWeakMap();myWeakmap.set(  document.getElementById('loGo'),  { timesClicked: 0 },);document.getElementById('logo').addEventListener('click', () => {  const logoData = myWeakmap.get(document.getElementById('logo'));  logoData.timesClicked++;}, false);

上面代码中,document.getElementById('logo') 是一个 DOM 节点,每当发生 click 事件,就更新一下状态。我们将这个状态作为值放在 WeakMap 里,对应的键就是这个节点对象。一旦这个 DOM 节点删除,该状态就会自动消失,不存在内存泄漏风险。

数据缓存

谜底就在谜面上,文章一开头我们提出的问题就是这里的答案。Vue 3 在实现响应式原理的时候就是使用了 WeakMap 来作为响应式对象的「缓存区」。

关于这一点用法也很简单,当我们需要关联对象和数据,比如在不修改原有对象的情况下储存某些属性或者根据对象储存一些计算的值等,而又不想手动去管理这些内存问题的时候就可以使用 WeakMap

部署类中的私有属性

WeakMap 的另一个用处是部署类中的私有属性。

值得一提的是,typescript 中已经实现的 private 私有属性原理就是利用 WeakMap

私有属性应该是不能被外界访问到,不能被多个实例共享,JavaScript 中约定俗成地使用下划线来标记私有属性和方法,一定程度来说是不靠谱的。

下面我们用三种方法来实现:

  • 版本一:闭包

const testFn = (function () {  let data;  class Test {    constructor(val) {      data = val    }    getData() {      return data;    }  }  return Test;})();let test1 = new testFn(3);let test2 = new testFn(4);console.log(test1.getData()); // 4console.log(test2.getData()); // 4

可以看到最后都输出 4,多实例共享私有属性了,所以版本一不符合。

  • 版本二:Symbol

const testFn = (function () {  let data = Symbol('data')  class Test {    constructor(val) {      this[data] = val    }    getData() {      return this[data]    }  }  return Test;})();let test1 = new testFn(3);let test2 = new testFn(4);console.log(test1.getData()); // 3console.log(test2.getData()); // 4console.log(test1[Object.getOwnPropertySymbols(test1)[0]]); // 3console.log(test2[Object.getOwnPropertySymbols(test2)[0]]); // 4

使用 Symbol 虽然实现了而且正确输出了 34,但是我们发现可以在外界不通过 getData 方法直接拿到私有属性,所以这种方法也不满足我们的要求。

  • 版本三:WeakMap

const testFn = (function () {  let data = new WeakMap()  class Test {    constructor(val) {      data.set(this, val)    }    getData() {      return data.get(this)    }  }  return Test;})();let test1 = new testFn(3);let test2 = new testFn(4);console.log(test1.getData()); // 3console.log(test2.getData()); // 4

到此,关于“Vue3中怎么用WeakMap作为缓存区”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

--结束END--

本文标题: Vue3中怎么用WeakMap作为缓存区

本文链接: https://www.lsjlt.com/news/302487.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Vue3中怎么用WeakMap作为缓存区
    这篇文章主要介绍“Vue3中怎么用WeakMap作为缓存区”,在日常操作中,相信很多人在Vue3中怎么用WeakMap作为缓存区问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Vue3中怎么用WeakMap作为...
    99+
    2023-06-22
  • Nodejs中的buffer缓存区的作用是什么
    这篇文章主要讲解了“Nodejs中的buffer缓存区的作用是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Nodejs中的buffer缓存区的作用是什...
    99+
    2022-10-19
  • DNS缓存中毒怎么工作的
    本篇内容介绍了“DNS缓存中毒怎么工作的”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!DNS缓存中毒是一种网络攻击,它使您的计算机误以为它会...
    99+
    2023-06-28
  • Spring中一级缓存、二级缓存和三级缓存有什么作用
    今天小编给大家分享一下Spring中一级缓存、二级缓存和三级缓存有什么作用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。缓存...
    99+
    2023-06-29
  • AngularJS中缓存怎么用
    这篇文章主要介绍了AngularJS中缓存怎么用,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。缓存篇一个缓存就是一个组件,它可以透明地储存数...
    99+
    2022-10-19
  • C#中缓存System.Web.Caching怎么用
    今天小编给大家分享一下C#中缓存System.Web.Caching怎么用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。Sy...
    99+
    2023-06-30
  • Spring Boot中怎么利用Redis 实现缓存操作
    这期内容当中小编将会给大家带来有关Spring Boot中怎么利用Redis 实现缓存操作,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。一、缓存的应用场景二、更新缓存的策略三、运行 springboot-...
    99+
    2023-06-17
  • 为什么要在 PHP shell 中使用缓存路径?
    PHP shell 是 PHP 编程语言的一个交互式环境,它可以让我们在命令行中直接执行 PHP 代码。在实际的开发中,我们经常需要在 PHP shell 中测试一些代码,以验证其正确性或者快速地尝试一些新的语法特性。然而,PHP shel...
    99+
    2023-06-26
    shell 缓存 path
  • PHP中为什么需要使用Memcached缓存技术
    在现代 Web 应用中,数据的高效访问对于应用的性能至关重要。PHP 作为一种流行的 Web 开发语言,其在应用中的数据读写性能也成为了十分关注的话题。为了提升 PHP 应用的性能,很多开发者就开始使用各种各样的缓存技术,其中最为常用的就是...
    99+
    2023-05-15
    PHP memcached 缓存技术
  • Vue3中怎么引入Pinia存储库并使用
    本篇内容主要讲解“Vue3中怎么引入Pinia存储库并使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Vue3中怎么引入Pinia存储库并使用”吧!用自己最喜欢的方式安装yarn a...
    99+
    2023-07-05
  • python中自带缓存lru_cache怎么用
    这篇文章给大家分享的是有关python中自带缓存lru_cache怎么用的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。1. lru_cache的使用1.1 参数详解以下是lru_cache方法的实现,我们看出可供...
    99+
    2023-06-20
  • Golang中的缓存库freecache怎么用
    这篇文章主要讲解了“Golang中的缓存库freecache怎么用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Golang中的缓存库freecache怎么用”吧!go开发缓存场景一般使用m...
    99+
    2023-06-29
  • java中字符流缓冲区的作用是什么
    本篇文章为大家展示了java中字符流缓冲区的作用是什么,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。1. 为什么要缓冲区?程序频繁地操作一个资源(如文件),则性能会很低,此时为了提升性能,就可以将一...
    99+
    2023-05-31
    java 字符流缓冲区
  • jQuery中数据缓存$.data怎么使用
    这篇文章主要介绍“jQuery中数据缓存$.data怎么使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“jQuery中数据缓存$.data怎么使用”文章能帮助大家解决问题。一、实现原理:对于DOM...
    99+
    2023-07-04
  • odoo中怎么使用redis实现缓存
    本篇内容主要讲解“odoo中怎么使用redis实现缓存”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“odoo中怎么使用redis实现缓存”吧!Odoo中使用Redis实现缓存可以提高系统性能,避...
    99+
    2023-07-05
  • SpringBoot项目中怎么使用缓存Cache
    本文小编为大家详细介绍“SpringBoot项目中怎么使用缓存Cache”,内容详细,步骤清晰,细节处理妥当,希望这篇“SpringBoot项目中怎么使用缓存Cache”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧...
    99+
    2023-07-06
  • Spring Boot中怎么使用集中式缓存Redis
    本篇内容介绍了“Spring Boot中怎么使用集中式缓存Redis”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!动手试试User实体的定义...
    99+
    2023-06-27
  • 怎么在html5中使用offlline进行缓存
    本篇文章为大家展示了怎么在html5中使用offlline进行缓存,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。拿tomcat为例,在打开Tomcat 6.0\conf\web.xml文件,在文件的...
    99+
    2023-06-09
  • Redis中怎么使用缓存替换策略
    Redis中怎么使用缓存替换策略,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。1 概述在操作系统的页面管理中,内存会维护一部分数据以备进程使用,但是由于内存的大小必然是远远...
    99+
    2023-06-20
  • 怎么使用DataTable作为存储过程的参数
    小编给大家分享一下怎么使用DataTable作为存储过程的参数,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!  因为SQL Se...
    99+
    2022-10-18
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作