javascript 什么是ES2021(ES12)中的WeakRef和终结器

zqdjd7g9  于 2023-03-28  发布在  Java
关注(0)|答案(2)|浏览(298)

我想通过一个真实的简单的示例在何处使用它们来了解ES2021中的WeakRef和终结器是什么。
我知道,WeakRef是一个类,这将允许开发人员创建对对象的弱引用,而终结器或FinalizationRegistry允许您注册回调函数,当对象被垃圾收集时将调用这些函数

const myWeakRef = new WeakRef({
  name: 'Cache',
  size: 'unlimited'
})

// Log the value of "myWeakRef":
console.log(myWeakRef.deref())
wfsdck30

wfsdck301#

一如既往,MDN's docs help
WeakRef对象包含对对象的弱引用,称为其目标或referent。对对象的弱引用是不阻止对象被垃圾收集器回收的引用。相比之下,正常的(或强)引用将对象保留在内存中。当对象不再有任何对它的强引用时,JavaScript引擎的垃圾收集器可能会销毁对象并回收其内存。如果发生这种情况,您将无法再从弱引用中获取对象。
在JS的几乎所有其他部分,如果某个对象(A)持有对另一个对象(B)的引用,B将不会被垃圾收集,直到A也可以被完全垃圾收集。例如:

// top level
const theA = {};
(() => {
  // private scope
  const theB = { foo: 'foo' };
  theA.obj = obj;
})();

在这种情况下,theB将 * 永远 * 不会被垃圾收集(除非theA.obj被重新分配),因为顶层的theA包含一个属性,该属性持有对theB的引用;它是一个强引用,防止垃圾回收。
另一方面,WeakRef提供了一个可以访问对象的 Package 器,同时不会阻止该对象的垃圾收集。在WeakRef上调用deref()将返回对象 * 如果它还没有被垃圾收集 *。如果它已经被GC'd,.deref()将返回undefined
FinalizationRegistry处理类似的问题:
FinalizationRegistry对象允许您在对象被垃圾回收时请求回调。
首先定义注册表和要运行的回调函数,然后在注册表上调用要观察的对象.register。这将让您知道 * 确切的时间 * 某些内容被垃圾收集。例如,以下内容将在obj被回收后记录Just got GCd!

console.log('script starting...');

const r = new FinalizationRegistry(() => {
  console.log('Just got GCd!');
});
(() => {
  // private closure
  const obj = {};
  r.register(obj);
})();

您还可以在调用.register时传递一个值,该值在收集对象时传递给回调。
一个二个一个一个
将记录the object named "obj",它将被GC'd。
所有这一切都表明,对这些工具的需求很少。正如MDN所说:
正确使用FinalizationRegistry需要仔细考虑,如果可能的话,最好避免使用。避免依赖规范未保证的任何特定行为也很重要。何时,如何以及是否发生垃圾收集取决于任何给定JavaScript引擎的实现。您在一个引擎中观察到的任何行为在另一个引擎中可能不同,在同一引擎的另一个版本中,垃圾收集是一个很难解决的问题,JavaScript引擎的实现者们一直在不断地完善和改进他们的解决方案。
最好是让引擎本身尽可能地自动处理垃圾收集,除非您有非常好的理由自己关心它。

htzpubme

htzpubme2#

弱引用的主要用途是实现对大型对象的缓存或Map。在许多情况下,我们不想长时间保留大量内存来保存这些很少使用的缓存或Map。我们可以允许内存很快被垃圾收集,如果我们再次需要它,我们可以生成一个新的缓存。如果变量不再可访问,JavaScript垃圾收集器会自动删除它。

const callback = () => {
  const aBigObj = {
    name: "Hello world"
  };
  console.log(aBigObj);
}

(async function(){
  await new Promise((resolve) => {
    setTimeout(() => {
      callback();
      resolve();
    }, 2000);
  });
})();

当执行上面的代码时,它会在2秒后打印“Hello world”。基于我们如何使用callback()函数,aBigObj可能会永远存储在内存中。
让我们将aBigObj设为弱引用。

const callback = () => {
  const aBigObj = new WeakRef({    name: "Hello world"  });  console.log(aBigObj.deref().name);}

(async function(){
  await new Promise((resolve) => {
    setTimeout(() => {
      callback(); // Guaranteed to print "Hello world"
      resolve();
    }, 2000);
  });

  await new Promise((resolve) => {
    setTimeout(() => {
      callback(); // No Gaurantee that "Hello world" is printed
      resolve();
    }, 5000);
  });
})();

第一个setTimeout()肯定会打印名称的值。这在创建弱引用后的第一轮事件循环中得到保证。
但是不能保证第二个setTimeout()会打印“Backbencher”。它可能已经被垃圾收集器清除了。由于垃圾收集在不同的浏览器中工作方式不同,我们不能保证输出。这也是为什么我们在该高速缓存等情况下使用WeakRef。

**一个

相关问题