在connectedCallback中等待Element Upgrade:FireFox和Chromium差异

Dan*_*man 10 callback class-method web-component custom-element

2023 年 3 月更新

注意:这是有效的,因为在下一个刻度中,lightDOM 中的N 个(不是全部!)DOM 元素将被解析。

对于 (app.) N > 1000你会遇到麻烦,因为延迟将在解析所有 N 个元素之前结束。

因此,要么添加(大约 20 行)代码来实际检查所有 lightDOM 是否已解析。(但是由于您的 DOM 正在遭受 Obesitas 的困扰,因此您可能还会遇到其他性能问题)

或者只是保持 lightDOM中N 个 DOM 元素的数量较小。

当然,您稍后在解析之后添加的任何 DOM都不会影响任何内容(当不触发时)connectedCallback

2021 年 3 月更新:

FireFox 错误已修复,现在的行为与 Chromium 和 Safari 相同。

这意味着等待 JS EventLoop 为空(带有setTimeoutrequestAnimationFrame)现在connectedCallback是一个跨浏览器方法

connectedCallback(){
 setTimeout(()=>{
   // can access lightDOM here
 }); // ,0 not required
}
Run Code Online (Sandbox Code Playgroud)

事件循环到底是什么?- 菲利普·罗伯茨
https://www.youtube.com/watch?v=8aGhZQkoFbQ



2020 年 10 月 28 日更新:



五月第一篇文章。2020年:

在使用 FireFox 一周后,再次遇到 Chrome Element 升级问题。

在交付给 Chromium 浏览器之前忘记将代码包装在 setTimeout 中。

  • FireFox 打印:ABCD

  • 铬印:ADCD

问题:为什么有区别?

connectedCallback(){
 setTimeout(()=>{
   // can access lightDOM here
 }); // ,0 not required
}
Run Code Online (Sandbox Code Playgroud)

历年相关回答:

更新#1

  • Apple/Safari:打印:ADCD (与 Chromium 相同)

注意:Chromium Blink 引擎是 Apples (WebKit)WebCore代码的一个分支!

更新#2

通过 Supersharps 参考,我们找到了相关线程:

FireFox 与 Chromium 中的回调顺序:

来源: https: //jsfiddle.net/WebComponents/9p5qyk1z/

Sup*_*arp 5

我认为 Chrome/Safari 的行为对于初学者来说不太直观,但对于一些更复杂的场景(例如子自定义元素),它会更加一致。

请参阅下面的不同示例。他们在 Firefox 中表现得很奇怪......

另一个我没有勇气编写代码的用例:当解析文档时,也许你还没有得到文档的结尾。因此,当创建自定义元素时,在获得结束标记(永远不会到达)之前,您无法确定获得其所有子元素。

根据 WebKit 的 Ryosuke Niwa 的说法:

那么问题是,在解析所有子元素之前,该元素不会获得connectedCallback。例如,如果整个文档是单个自定义元素,则即使该元素确实位于文档中,该自定义元素也永远不会收到connectedCallback,直到整个文档被获取并解析为止。那会很糟糕。

因此,最好不要在创建自定义元素后立即等待并连接它,这意味着没有子元素。

<script>
    customElements.define( 'c-e', class extends HTMLElement {} ) 
    customElements.define('my-element', class extends HTMLElement {
      connectedCallback() {
        console.log(this.innerHTML, this.childNodes.length)
        let span = document.createElement( 'span' )
        if (this.innerHTML.indexOf( 'A' ) >= 0 )
            span.textContent = 'B'
        else
            span.textContent = 'D'
        setTimeout( () => this.appendChild( span ) )
      }
    })
</script>
<my-element>A</my-element><my-element>C</my-element>
<br>
<my-element><c-e></c-e>A</my-element><my-element>A<c-e></c-e></my-element>
<br>
<my-element><c-e2></c-e2>A</my-element><my-element>A<c-e2></c-e2></my-element>
Run Code Online (Sandbox Code Playgroud)

据我了解,对此达成了共识,导致以(Chrome/Safari)方式调整规范:

通过确保插入到 DOM 中立即触发connectedCallback,而不是将回调反应放在备份元素队列上并让它在下一个微任务检查点触发,修复了w3c/webcomponents#551 。这意味着connectedCallback通常会在元素有零个子元素时被调用,正如预期的那样,而不是根据何时看到下一个自定义元素的随机数。

connectedCallback我们可以得出结论,Firefox 也遵循该规范...是的,但由于上述原因,我们不应该依赖 中的内容。