callback - 在 connectedCallback 中等待 Element Upgrade:FireFox 和 Chromium 的区别
问题描述
2021 年 3 月更新:
修复了 FireFox 错误,现在的行为与 Chromium 和 Safari 相同。
这意味着等待 JS EventLoop 为空(使用setTimeout
or requestAnimationFrame
)connectedCallback
现在是一种跨浏览器方法
connectedCallback(){
setTimeout(()=>{
// can access lightDOM here
}); // ,0 not required
}
事件循环到底是什么?- 菲利普·罗伯茨
https://www.youtube.com/watch?v=8aGhZQkoFbQ
2020 年 10 月 28 日更新:
现在由 Mozilla 工程师 Anne van Kesteren 报告为 FireFox 中的一个错误:
FireFox 调用 connectedCallback 太晚了:
https ://bugzilla.mozilla.org/show_bug.cgi?id=1673811
五月第一次发帖。2020:
在使用 FireFox 一周后,再次被这个 Chrome Element 升级问题所困扰。
在交付给 Chromium 浏览器之前忘记将代码包装在 setTimeout 中。
火狐打印:ABCD
铬印刷品:ADCD
问题:为什么不同?
<script>
customElements.define('my-element', class extends HTMLElement {
connectedCallback() {
console.log(this.innerHTML);// "A" in FireFox, "" in other Browsers
if (this.innerHTML == "A")
this.innerHTML = this.innerHTML + "B";
else
setTimeout(() => this.innerHTML = this.innerHTML + "D");
}
})
</script>
<my-element>A</my-element><my-element>C</my-element>
过去几年的相关答案:
更新#1
- Apple/Safari:打印:ADCD (与 Chromium 相同)
注意:Chromium Blink 引擎是 Apples (WebKit)WebCore代码的一个分支!!
更新#2
通过 Supersharps 参考我们找到了相关的线程:
(2016)文档解析器创建自定义元素时的 connectedCallback 时间
https://github.com/w3c/webcomponents/issues/551(2019)需要回调子级更改或解析器完成子级解析
https://github.com/w3c/webcomponents/issues/809
FireFox 与 Chromium 中的回调顺序:
解决方案
我认为 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>
据我了解,对此达成共识,导致以(Chrome/Safari)方式调整规范:
修复w3c/webcomponents#551,确保插入 DOM 立即触发 connectedCallback,而不是将回调反应放在备份元素队列上并让它在下一个微任务检查点触发。这意味着 connectedCallback 通常会在元素有零个子元素时调用,正如预期的那样,而不是一个随机数,具体取决于何时看到下一个自定义元素。
connectedCallback
我们可以得出结论,Firefox 也遵循规范......是的,但由于上述原因,我们不应该依赖其中的内容。
推荐阅读
- r - 从插入符号的训练函数中提取预测
- python - 使用 Asyncio 模块多次调用 url,没有获得性能优势
- .net-core - dotnet核心控制台启动时如何运行特定服务
- javascript - 如何使用 JavaScript 打开锚上下文菜单?
- python - 人口增长
- javascript - 无法在数据库中插入多条记录
- python - 测试复杂数据结构中元素的 Pythonic 方法
- php - 权限被拒绝 laravel 中没有现有目录
- qt - 仅使用 conanfile.txt 和 bintray 将 Qt 5.14.2 与 conan 包管理器添加为 repo
- html - 如何在 Shopify Debut 主题的主导航中激活“商店”链接?