当 dom 中不再存在元素时,SetInterval 将 运行 保留在 webcomponent 中

SetInterval keeps running in webcomponent when element is not present in dom anymore

目前,我正在开发一个协调多个 Web 组件的简单应用程序。其中一个组件包含一个 setInterval 函数。该函数保留 运行,即使组件本身不再出现在 dom 中。谁能给我解释一下为什么会这样?

这是一个简单的复制:

const selectorEl = document.getElementsByTagName('body')[0];
selectorEl.innerHTML = '<my-component></my-component>'; // Append custom component to body

class WebComponent extends HTMLElement {
    constructor() {
        super();
        this.innerHTML = '<span>This should not be visible since I am removed instantly!</span>';
        setInterval(() => console.log('I am still running...'), 2000);
    }
}

window.customElements.define('my-component', WebComponent);
selectorEl.innerHTML = ''; // Remove element from the dom directly

您需要使用 disconnectedCallback 挂钩,一旦组件从 dom 中移除,它就会被调用,因此在此函数中,您可以清除间隔。

disconnectedCallback() {
  clearInterval(interval)
}

您需要使用lifecycle callbacks才能正确使用setIntervalclearInterval

示例如下:

const selectorEl = document.getElementsByTagName("body")[0];
selectorEl.innerHTML = "<my-component></my-component>"; // Append custom component to body

class WebComponent extends HTMLElement {

  connectedCallback() {
    this.innerHTML =
      "<span>This should not be visible since I am removed instantly!</span>";
  
    this.interval = setInterval(
      () => console.log("I am still running...", Math.random()),
      2000
    );
  }

  disconnectedCallback() {
    clearInterval(this.interval);
  }
}

window.customElements.define("my-component", WebComponent);
setTimeout(() => selectorEl.innerHTML = "",7000); // Remove element from the dom directly

Web 组件有自己的生命周期,当一个元素从 DOM 中删除时,disconnectedCallback() 将被调用。当元素从 DOM 中移除时,会调用生命周期钩子。因此,它是添加清理逻辑和释放资源的理想场所。在您的情况下,请调用 clearInterval 方法,该方法会像您所做的那样清除使用 setInterval() 方法设置的计时器。

disconnectedCallback() {
   clearInterval(interval)
}

一个更简洁的例子:

<script>
  customElements.define("my-component", class extends HTMLElement {
    connectedCallback() {
      console.log("connectedCallback" , this.isConnected);
      this.innerHTML = "A Web Component";
      setTimeout(() => this.remove(), 2000); // triggers disconnectedCallback
      this.interval = setInterval(() => this.innerHTML += ".", 50);
    }

    disconnectedCallback() {
      console.log("disconnectedCallback" , this.isConnected);
      clearInterval(this.interval);
    }
  });
</script>
<my-component></my-component>

备注

  • DOM 元素不再存在于 disconnectedCallback 中,但 Web 组件仍存在于内存中,因此您可以访问之前创建(或附加)的任何内容

  • Drag/drop 或 append 操作触发 disconnectedVCallback 然后 再次触发 connectedCallback