ES6 WeakMap的实际用途是什么? [英] What are the actual uses of ES6 WeakMap?

查看:135
本文介绍了ES6 WeakMap的实际用途是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在ECMAScript 6中引入的 WeakMap 数据结构的实际用途是什么?



弱图创建了对其值的强参考,确保已插入弱地图中的值永远不会消失,只要其键仍然存在,则不能用于备注表,缓存或其他任何您通常使用弱引用的地图,弱值等的地图等。



在我看来,这样:

  weakmap.set(key,value); 

...只是一个迂回的方式说:

  key.value = value; 

我缺少什么具体的用例?

解决方案

基本上



WeakMaps提供了一种从外部扩展对象而不干扰垃圾收集的方式。 >每当你想扩展一个对象,但是不能因为它是密封的 - 或者从外部的源 - 可以应用WeakMap。



WeakMap是一个映射(字典),其中较弱 - 也就是说,如果所有对键的引用丢失,并且没有更多的值引用 - 可以垃圾收集。让我们先来看一下这个例子,然后再解释一下,最后完成一个真正的使用。



假设我正在使用一个给我一个特定对象的API:

  var obj = getObjectFromLibrary(); 

现在,我有一个使用该对象的方法:

  function useObj(obj){
doSomethingWith(obj);
}

我想跟踪一下方法被调用了多少次对象和报告如果发生超过N次。真的会想到使用地图:

  var map = new Map(); // map可以有对象键
函数useObj(obj){
doSomethingWith(obj);
var called = map.get(obj)|| 0;
调用++; //再次调用一次
if(称为> 10)report(); //报告调用超过10次
map.set(obj,调用);
}

这有效,但它有内存泄漏 - 我们现在跟踪每一个传递给函数的单个库对象保持库对象不被垃圾回收。相反,我们可以使用 WeakMap

  var map = new WeakMap (); //创建一个弱映射
函数useObj(obj){
doSomethingWith(obj);
var called = map.get(obj)|| 0;
调用++; //再次调用一次
if(称为> 10)report(); //报告调用超过10次
map.set(obj,调用);
}

内存泄漏已经消失。



用例



有些用例会导致内存泄漏,并由 WeakMap 包括:




  • 保存关于特定对象的私人数据,只允许访问者参考地图。一个更特殊的方法是使用私有符号提案,但是从现在开始很长一段时间。

  • 保存关于库对象的数据,而不改变它们或引起开销。

  • 保存关于类型多的对象的一小部分对象的数据,不存在隐藏类的问题JS引擎用于相同类型的对象。

  • 在浏览器中保存关于主机对象(如DOM节点)的数据。

  • 从外部添加对象的功能(如另一个答案中的事件发射器示例) li>


我们来看一个真正的用法



它可以用来扩展一个对象从外部。让我们从io.js的现实世界中给出一个实际的(适应性的,真实的 - 例证)的例子。



让我们说你是NodeJS,你有承诺对象 - 现在您想要跟踪所有当前被拒绝的承诺 - 但是您不要 希望避免垃圾回收他们没有参考。



现在,您不想希望将属性添加到本机对象,原因很明显,所以你被卡住了。如果您保留对承诺的引用,则会导致内存泄漏,因为不会发生垃圾回收 - 如果不保留引用,则无法保存有关个人承诺的其他信息。任何涉及保存承诺ID的计划本来就意味着您需要参考。



输入WeakMaps



WeakMaps表示较弱。没有办法枚举弱地图或获取其所有值。在弱映射中,您可以根据密钥存储数据,并在密钥得到垃圾回收时执行这些值。



这意味着给定承诺可以存储状态关于它 - 该对象仍然可以被垃圾收集。后来如果你得到一个对象的引用,你可以检查你是否有任何与之相关的状态并报告。



这是用来实现被处理的拒绝挂钩由Petka Antonov作为这个

  process.on('unhandledRejection',function(reason,p){
console.log(未处理的拒绝在:Promise,p,reason:,reason);
//应用程序特定的日志记录,抛出错误或其他逻辑
});

我们在地图中保留有关承诺的信息,并可以知道何时处理被拒绝的承诺。 >

What are the actual uses of the WeakMap data structure introduced in ECMAScript 6?

Since a key of a weak map creates a strong reference to its corresponding value, ensuring that a value which has been inserted into a weak map will never disappear as long as its key is still alive, it can't be used for memo tables, caches or anything else that you would normally use weak references, maps with weak values, etc. for.

It seems to me that this:

weakmap.set(key, value);

...is just a roundabout way of saying this:

key.value = value;

What concrete use cases am I missing?

解决方案

Fundamentally

WeakMaps provide a way to extend objects from the outside without interfering with garbage collection. Whenever you want to extend an object but can't because it is sealed - or from an external source - a WeakMap can be applied.

A WeakMap is a map (dictionary) where the keys are weak - that is, if all references to the key are lost and there are no more references to the value - the value can be garbage collected. Let's show this first through examples, then explain it a bit and finally finish with a real use.

Let's say I'm using an API that gives me a certain object:

var obj = getObjectFromLibrary();

Now, I have a method that uses the object:

function useObj(obj){
   doSomethingWith(obj);
}

I want to keep track of how many times the method was called with a certain object and report if it happens more than N times. Naively one would think to use a Map:

var map = new Map(); // maps can have object keys
function useObj(obj){
    doSomethingWith(obj);
    var called = map.get(obj) || 0;
    called++; // called one more time
    if(called > 10) report(); // Report called more than 10 times
    map.set(obj, called);
}

This works, but it has a memory leak - we now keep track of every single library object passed to the function which keeps the library objects from ever being garbage collected. Instead - we can use a WeakMap:

var map = new WeakMap(); // create a weak map
function useObj(obj){
    doSomethingWith(obj);
    var called = map.get(obj) || 0;
    called++; // called one more time
    if(called > 10) report(); // Report called more than 10 times
    map.set(obj, called);
}

And the memory leak is gone.

Use cases

Some use cases that would otherwise cause a memory leak and are enabled by WeakMaps include:

  • Keeping private data about a specific object and only giving access to it to people with a reference to the Map. A more ad-hoc approach is coming with the private-symbols proposal but that's a long time from now.
  • Keeping data about library objects without changing them or incurring overhead.
  • Keeping data about a small set of objects where many objects of the type exists to not incur problems with hidden classes JS engines use for objects of the same type.
  • Keeping data about host objects like DOM nodes in the browser.
  • Adding a capability to an object from the outside (like the event emitter example in the other answer).

Let's look at a real use

It can be used to extend an object from the outside. Let's give a practical (adapted, sort of real - to make a point) example from the real world of io.js.

Let's say you're NodeJS and you have Promise objects - now you want to keep track of all the currently rejected promises - however you do not want to keep them from being garbage collected in case no references exist to them.

Now, you don't want to add properties to native objects for obvious reasons - so you're stuck. If you keep references to the promises you're causing a memory leak since no garbage collection can happen - if you don't keep references you can't save additional information about individual promises. Any scheme that involves saving the ID of a promise inherently means you need a reference to it.

Enter WeakMaps

WeakMaps mean that the keys are weak. There are no ways to enumerate a weak map or to get all its values. In a weak map you can store the data based on a key and when the key gets garbage collected so do the values.

This means that given a promise you can store state about it - and that object can still be garbage collected. Later on if you get a reference to an object you can check if you have any state relating to it and report it.

This was used to implement unhandled rejection hooks by Petka Antonov as this:

process.on('unhandledRejection', function(reason, p) {
    console.log("Unhandled Rejection at: Promise ", p, " reason: ", reason);
    // application specific logging, throwing an error, or other logic here
});

We keep information about promises in a map and can know when a rejected promise was handled.

这篇关于ES6 WeakMap的实际用途是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆