【问题标题】:SetInterval keeps running in webcomponent when element is not present in dom anymore当 dom 中不再存在元素时,SetInterval 继续在 webcomponent 中运行
【发布时间】:2022-01-20 10:29:28
【问题描述】:

目前,我正在开发一个可以编排多个 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

【问题讨论】:

  • setInterval 将一直运行,直到您调用 clearInterval,它与 DOM 无关。
  • “即使组件本身不再存在于 dom 中,该功能也会继续运行。有人可以向我解释为什么会这样吗?” - 因为有这两件事之间绝对没有关系......?!?从现在开始,您指示浏览器每隔一段时间执行一个函数。 DOM 与这...有什么关系?
  • 谢谢,基思。你知道如果它们没有清理这个逻辑,是否可以强制停止 web 组件内的所有运行间隔?
  • 您可能希望使用生命周期回调,developer.mozilla.org/en-US/docs/Web/Web_Components/…
  • @Tom 如果您不使用泄漏计时器控制 Web 组件,您可以 proxy 窗口计时器(timeoutinterval)以维护您自己的计时器 ID 列表和根据您自己的标准清除它们。

标签: javascript typescript setinterval web-component


【解决方案1】:

您需要使用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

【讨论】:

  • 警告!此代码在document.createElement("my-component"); 上失败,因为constructor 不应添加DOM 元素,该工作应在connectedCallback 中完成。只有当您在 conctructor 中创建 shadowRoot 时,您才能添加 HTML(到 shadowDOM)
  • @Danny'365CSI'Engelman,非常感谢您对这个问题的关注。我错过了这一点并在代码中更正了它:)
【解决方案2】:

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

disconnectedCallback() {
  clearInterval(interval)
}

【讨论】:

    【解决方案3】:

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

    disconnectedCallback() {
       clearInterval(interval)
    }
    

    【讨论】:

      【解决方案4】:

      一个更简洁的例子:

      <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>

      注意事项

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

      • 拖放或append 操作触发disconnectedVCallback 然后再次触发connectedCallback

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-02-11
        • 1970-01-01
        • 1970-01-01
        • 2019-12-07
        • 2023-03-19
        • 2017-07-29
        • 2021-03-01
        相关资源
        最近更新 更多