代码之家  ›  专栏  ›  技术社区  ›  Jose Carlos Ramírez

一个从未兑现的承诺会导致内存泄漏吗?

  •  2
  • Jose Carlos Ramírez  · 技术社区  · 1 年前

    这个问题在SO上并不新鲜,但我有一个与其他问题不完全相同的场景。

    假设我有课 Component

    class Component {
      constructor() {
        this.resolvers = [];
      }
    
      addResolver() {
        return new Promise((resolve) => {
          this.resolvers.push(resolve);
        });
      }
    
      callResolvers() {
        this.resolvers.forEach((resolver) => resolver());
      }
    }
    

    然后我得到了这段代码

    let components = [];
    
    async function addComponent() {
      const component = new Component();
    
      components.push(component);
    
      await component.addResolver();
    
      console.log("resolver called");
    }
    
    function deleteComponents() {
      components = [];
    }
    
    function resolveComponents() {
      components.forEach((component) => component.callResolvers());
    }
    
    addComponent();
    addComponent();
    addComponent();
    
    resolveComponents();
    

    如果我打电话 resolveComponents() 解析器被调用。

    我担心的是 resolveComponents() ,我打电话 deleteComponents() ,如下所示:

    addComponent();
    addComponent();
    addComponent();
    
    deleteComponents();
    

    这些垃圾会收集组件吗?

    他们有未兑现的承诺,这些承诺的解决方案存储在 component.resolvers

    由于之前的组件在删除后将无法访问,我的猜测是,即使它们有未兑现的承诺,它们也会被收集起来。

    这个问题的答案是什么?

    3 回复  |  直到 1 年前
        1
  •  2
  •   Guerric P    1 年前

    A. Promise 只是一个常规对象,因此如果不再引用它,那么它将被垃圾收集器清除(即使处于挂起状态)。如果 许诺 稍后解析,那么很明显在某个地方引用了它。例如,在此代码中:

    new Promise(resolve => setTimeout(resolve, 999999));
    

    即使我们不存储 许诺 在变量中, setTimeout 保留对 resolve 函数,该函数内部引用 this : 许诺 例子然后 许诺 实例保持活动状态,直到延迟结束。

    在您的示例中,如果将组件数组替换为空数组,则组件及其 resolvers 属性,该属性只包含对Promises的引用,因此也可以收集它们。

    如果你对内存泄漏有疑问,你可以通过浏览器DevTools的“内存”选项卡拍摄内存快照来轻松诊断。

        2
  •  1
  •   Vivick    1 年前

    您没有循环依赖项,并且调用 deleteComponents 让我们放弃你对他们的唯一参考。这样部件就不会泄漏

        3
  •  1
  •   z3db0y    1 年前

    如果没有提到承诺,并且它超出了范围,那么它很可能有资格获得GC,尽管我不能100%确定情况是否如此。解决您的任何承诺通常是一种很好的做法,因此我建议在删除组件之前调用解析器。