当 dom 中不再存在元素时,SetInterval 继续在 webcomponent 中运行

Posted

技术标签:

【中文标题】当 dom 中不再存在元素时,SetInterval 继续在 webcomponent 中运行【英文标题】:SetInterval keeps running in webcomponent when element is not present in dom anymore 【发布时间】: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 窗口计时器(timeout 和 interval)以维护您自己的计时器 ID 列表和根据您自己的标准清除它们。 【参考方案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

【讨论】:

以上是关于当 dom 中不再存在元素时,SetInterval 继续在 webcomponent 中运行的主要内容,如果未能解决你的问题,请参考以下文章

Capybara/Cucumber In Ruby:当不再存在元素时停止搜索

Python,Selenium:'元素不再附加到 DOM'

Internet Explorer:当目标 DOM 元素在 DOM 中移动时,悬停状态变为粘滞状态

当事件触发并尝试在不再存在的对象中执行事件处理程序时会发生啥?

赛普拉斯:测试元素是不是不存在

Python Selenium:等到元素不再陈旧?