WebComponent の初期化順
- カテゴリ:
- JavaScript
- コメント数:
- Comments: 0
◆ 初期化順が安定しない
準備
outer-html の中に inner-html がある構造にします[main.html]
<!doctype html>
<meta charset="utf-8"/>
<link rel="import" href="component.html">
<script>
</script>
<outer-elem></outer-elem>
<meta charset="utf-8"/>
<link rel="import" href="component.html">
<script>
</script>
<outer-elem></outer-elem>
[component.html]
<template>
<inner-elem></inner-elem>
</template>
<script>
{
const doc = document.currentScript.ownerDocument
customElements.define("inner-elem", class extends HTMLElement {
constructor() {
super()
this.value = 0
}
})
customElements.define("outer-elem", class extends HTMLElement {
constructor() {
super()
const template = doc.querySelector("template")
this.attachShadow({ mode: "open" }).append(template.content.cloneNode(true))
this.shadowRoot.querySelector("inner-elem").value = 1
}
})
}
</script>
<inner-elem></inner-elem>
</template>
<script>
{
const doc = document.currentScript.ownerDocument
customElements.define("inner-elem", class extends HTMLElement {
constructor() {
super()
this.value = 0
}
})
customElements.define("outer-elem", class extends HTMLElement {
constructor() {
super()
const template = doc.querySelector("template")
this.attachShadow({ mode: "open" }).append(template.content.cloneNode(true))
this.shadowRoot.querySelector("inner-elem").value = 1
}
})
}
</script>
inner-elem のコンストラクタで value プロパティを 0 に初期化します
outer-elem で inner-elem を含む ShadowDOM を作ったあとに inner-elem の value プロパティを 1 に設定しています
outer-elem で append したときに inner-elem が初期化されていてその後に inner-elem にアクセスして value を書き換えるので 1 での上書きが後から実行される……と思うのですが安定しません
空 script の有無で違う
main.html を開くと0
main.html の空 <script> を消すと
1
になります
template の有無で違う
outer-elem のコンストラクタで template 使わないようにしますconstructor() {
super()
this.attachShadow({ mode: "open" }).append(document.createElement("inner-elem"))
this.shadowRoot.querySelector("inner-elem").value = 1
}
super()
this.attachShadow({ mode: "open" }).append(document.createElement("inner-elem"))
this.shadowRoot.querySelector("inner-elem").value = 1
}
これだと空 script の有無によらずに
1
でした
import の有無で違う
main.html のインポートをなくして直接書きます<!doctype html>
<meta charset="utf-8"/>
<template>
<inner-elem></inner-elem>
</template>
<script>
{
const doc = document.currentScript.ownerDocument
customElements.define("inner-elem", class extends HTMLElement {
constructor() {
super()
this.value = 0
}
})
customElements.define("outer-elem", class extends HTMLElement {
constructor() {
super()
const template = doc.querySelector("template")
this.attachShadow({ mode: "open" }).append(template.content.cloneNode(true))
this.shadowRoot.querySelector("inner-elem").value = 1
}
})
}
</script>
<script>
</script>
<outer-elem></outer-elem>
<meta charset="utf-8"/>
<template>
<inner-elem></inner-elem>
</template>
<script>
{
const doc = document.currentScript.ownerDocument
customElements.define("inner-elem", class extends HTMLElement {
constructor() {
super()
this.value = 0
}
})
customElements.define("outer-elem", class extends HTMLElement {
constructor() {
super()
const template = doc.querySelector("template")
this.attachShadow({ mode: "open" }).append(template.content.cloneNode(true))
this.shadowRoot.querySelector("inner-elem").value = 1
}
})
}
</script>
<script>
</script>
<outer-elem></outer-elem>
これだと空 script の有無によらずに
0
こちらも outer-elem のコンストラクタで template を使わないようにすると
1
実行順がはっきり決まってないと使いづらいです
初期化済みフラグつけて outer-elem から値を変更するときにまだ初期化されてないなら初期化するまで後回しにするとかするしかないのでしょうか