一尘不染

ES6 WeakMap的实际用途是什么?

javascript

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

由于弱映射的键会对其对应的值建立强引用,因此确保只要弱键仍处于活动状态,插入到弱映射中的值就 永远不会
消失,因此不能将其用于备忘录表,缓存或通常使用弱引用,具有弱值的映射等的其他任何内容。

在我看来,这是:

weakmap.set(key, value);

…只是一种回旋的说法:

key.value = value;

我缺少哪些具体用例?


阅读 431

收藏
2020-05-01

共1个答案

一尘不染

从根本上

WeakMaps提供了一种从外部扩展对象而不干扰垃圾回收的方法。
每当您想扩展对象但由于密封而不能扩展对象时(或者从外部源扩展)时,都可以应用WeakMap。

WeakMap是 弱的映射(字典),也就是说,如果丢失了对 键的 所有引用,并且不再有对该值的引用,则可以对
进行垃圾回收。让我们首先通过示例展示它,然后进行一些解释,最后完成实际使用。

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

var obj = getObjectFromLibrary();

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

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

我想跟踪用某个对象调用该方法的次数,并报告该方法是否发生了N次以上。天真的会想到使用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);
}

这可行,但是会发生内存泄漏-我们现在跟踪传递给该函数的每个库对象,从而避免垃圾回收。相反-我们可以使用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);
}

并且内存泄漏消失了。

用例

可能会导致内存泄漏并由启用的一些用例WeakMap包括:

  • 保留有关特定对象的私人数据,并且仅授予参考地图的人员访问。私有符号提案中出现了一种更特殊的方法,但是距离现在已经很久了。
  • 保留有关库对象的数据,而无需更改它们或引起开销。
  • 保留有关少量对象的数据(其中存在许多类型的对象)不会引起JS引擎用于相同类型的对象的隐藏类问题。
  • 在浏览器中保留有关主机对象(如DOM节点)的数据。
  • 从外部向对象添加功能(如另一个答案中的事件发射器示例)。

让我们看一下真正的用途

它可用于从外部扩展对象。让我们从Node.js的真实世界中给出一个实用的(经过改编的,真实的)实例。

比方说,你的Node.js,你有Promise对象-现在你想跟踪所有当前被拒绝承诺-然而,你 希望让他们被的情况下,垃圾收集没有引用存在于他们。

现在,你 希望将属性添加到显而易见的原因,本地对象-
这样你就完蛋了。如果保留对Promise的引用,则将导致内存泄漏,因为不会发生垃圾回收。如果您不保留引用,那么您将无法保存有关单个承诺的其他信息。任何涉及保存承诺ID的方案本质上都意味着您需要对其进行引用。

输入弱地图

WeakMaps表示 很弱。无法枚举弱映射或获取其所有值。在弱映射中,您可以基于密钥存储数据,并且在密钥被垃圾回收时也可以存储值。

这意味着只要有一个承诺,您就可以存储有关它的状态-
而且该对象仍可以被垃圾回收。稍后,如果您获得对对象的引用,则可以检查是否具有与该对象有关的任何状态并报告该对象。

Petka Antonov用来实现未处理的拒绝挂钩,如下所示:

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
});

我们将有关诺言的信息保存在地图中,并且可以知道何时处理了被拒绝的诺言。

2020-05-01