async=false が async=false してくれない
- カテゴリ:
- JavaScript
- コメント数:
- Comments: 0
◆ 動的に追加したasync=false の script タグと HTML に直接書かれているタグでは扱いが違う
◆ パースされて head タグに加えられていなくても すでにリクエストされているので DOM の順番と実行される順番が違うことがある
◆ 動的に追加する script タグの後に実行したいスクリプトなら それも動的にロードして async=false で順番に実行するのがよさそう
◆ パースされて head タグに加えられていなくても すでにリクエストされているので DOM の順番と実行される順番が違うことがある
◆ 動的に追加する script タグの後に実行したいスクリプトなら それも動的にロードして async=false で順番に実行するのがよさそう
async を false にすると順番に読み込んでくれるのですが JavaScript で動的に追加したものしかだめなようです
loadFile は指定 url のファイルを async = false で document.head に append する関数です
[test.js]
1 つめの script タグで loadFile("test.js") をしているので HTML での 2 つめの script タグより先に test.js が DOM上は設置されてるはずです
なので 先に val が 200 にされてから console.log の表示にうつるように思えます
ですが
途中にある HTML は document.head の innerHTML で test.js のあとに console.log があります
なのに loadFile で読み込んだファイルが後から実行されています
[main.html]
[test2.js]
変わらず loadFile 関数を使ったものが後から実行されます
[main.html]
ちゃんと test.js → test2.js の流れで実行されています
DOM 構築時の順番じゃなくて HTML に直接書いたものが優先されるみたい
[main.html]
test2.js を読み込む前に script タグを 5 つ用意してだいたい 1~2 秒かかります
この時間の間で test.js は読みこまれていて test2.js はまだ読みこまれていないのでいけるかな と思ったけど
だめでした
[main.html]
すると
なんと test.js を先に読みこんでくれています
原因がよくわからない・・・
すると test2 はまだ DOM では作られていないのにすでに Network の一覧にありました
つまり DOM 構築前にパースは終わっていてリクエストは先に送っているみたいです
それでも DOM が多すぎると一度に全部パースはしないで区切ってるのか test2.js が先にリクエストしないことがあります
その場合は test.js が先にロードされて順番が変わるということだと思います
なんか複雑
とりあえず HTML に最初から書いているのと 動的に追加するものでロード順は決まらないので 動的なロードの後に 実行したいのなら非同期処理を考慮するように作るか 動的処理が絡むところ以降は全部動的にロードして async=false で順番制御がよさそうです
* これはあくまで Chrome での調査結果です
1
[main.html]<!doctype html>
<meta charset="utf-8">
<script>
var val = 100
function loadFile(url){
var s = document.createElement("script")
s.async = false
s.src = url
document.head.appendChild(s)
}
loadFile("test.js")
</script>
<script>
console.log(val)
console.log(document.head.innerHTML)
</script>
<meta charset="utf-8">
<script>
var val = 100
function loadFile(url){
var s = document.createElement("script")
s.async = false
s.src = url
document.head.appendChild(s)
}
loadFile("test.js")
</script>
<script>
console.log(val)
console.log(document.head.innerHTML)
</script>
loadFile は指定 url のファイルを async = false で document.head に append する関数です
[test.js]
val = 200
console.log("loaded test")
console.log("loaded test")
1 つめの script タグで loadFile("test.js") をしているので HTML での 2 つめの script タグより先に test.js が DOM上は設置されてるはずです
なので 先に val が 200 にされてから console.log の表示にうつるように思えます
ですが
100
<meta charset="utf-8">
<script>
var val = 100
function loadFile(url){
var s = document.createElement("script")
s.async = false
s.src = url
document.head.appendChild(s)
}
loadFile("test.js")
</script><script src="test.js"></script>
<script>
console.log(val)
console.log(document.head.innerHTML)
</script>
loaded test
<meta charset="utf-8">
<script>
var val = 100
function loadFile(url){
var s = document.createElement("script")
s.async = false
s.src = url
document.head.appendChild(s)
}
loadFile("test.js")
</script><script src="test.js"></script>
<script>
console.log(val)
console.log(document.head.innerHTML)
</script>
loaded test
途中にある HTML は document.head の innerHTML で test.js のあとに console.log があります
なのに loadFile で読み込んだファイルが後から実行されています
2
HTML での 2 番目の script がソースに直接書いてるから defer 無効化みたいな感じで特別扱いされてるのかなと test2.js に置き換えてみます[main.html]
<!doctype html>
<meta charset="utf-8">
<script>
var val = 100
function loadFile(url){
var s = document.createElement("script")
s.async = false
s.src = url
document.head.appendChild(s)
}
loadFile("test.js")
</script>
<script src="test2.js"></script>
<meta charset="utf-8">
<script>
var val = 100
function loadFile(url){
var s = document.createElement("script")
s.async = false
s.src = url
document.head.appendChild(s)
}
loadFile("test.js")
</script>
<script src="test2.js"></script>
[test2.js]
console.log(val)
console.log(document.head.innerHTML)
console.log(document.head.innerHTML)
100
<meta charset="utf-8">
<script>
var val = 100
function loadFile(url){
var s = document.createElement("script")
s.async = false
s.src = url
document.head.appendChild(s)
}
loadFile("test.js")
</script><script src="test.js"></script>
<script src="test2.js"></script>
loaded test
<meta charset="utf-8">
<script>
var val = 100
function loadFile(url){
var s = document.createElement("script")
s.async = false
s.src = url
document.head.appendChild(s)
}
loadFile("test.js")
</script><script src="test.js"></script>
<script src="test2.js"></script>
loaded test
変わらず loadFile 関数を使ったものが後から実行されます
3
async=false の動作が変わったとかないよね とtest.js と test2.js の両方とも loadFile にして確認してみます[main.html]
<!doctype html>
<meta charset="utf-8">
<script>
var val = 100
function loadFile(url){
var s = document.createElement("script")
s.async = false
s.src = url
document.head.appendChild(s)
}
loadFile("test.js")
loadFile("test2.js")
</script>
<meta charset="utf-8">
<script>
var val = 100
function loadFile(url){
var s = document.createElement("script")
s.async = false
s.src = url
document.head.appendChild(s)
}
loadFile("test.js")
loadFile("test2.js")
</script>
loaded test
200
<meta charset="utf-8">
<script>
var val = 100
function loadFile(url){
var s = document.createElement("script")
s.async = false
s.src = url
document.head.appendChild(s)
}
loadFile("test.js")
loadFile("test2.js")
</script><script src="test.js"></script><script src="test2.js"></script>
200
<meta charset="utf-8">
<script>
var val = 100
function loadFile(url){
var s = document.createElement("script")
s.async = false
s.src = url
document.head.appendChild(s)
}
loadFile("test.js")
loadFile("test2.js")
</script><script src="test.js"></script><script src="test2.js"></script>
ちゃんと test.js → test2.js の流れで実行されています
DOM 構築時の順番じゃなくて HTML に直接書いたものが優先されるみたい
4
delay をさせてみます[main.html]
<!doctype html>
<meta charset="utf-8">
<script>
var val = 100
function loadFile(url){
var s = document.createElement("script")
s.async = false
s.src = url
document.head.appendChild(s)
}
loadFile("test.js")
</script>
<script>for(var i=0;i<100000000;i++) i</script>
<script>for(var i=0;i<100000000;i++) i</script>
<script>for(var i=0;i<100000000;i++) i</script>
<script>for(var i=0;i<100000000;i++) i</script>
<script>for(var i=0;i<100000000;i++) i</script>
<script src="test2.js"></script>
<meta charset="utf-8">
<script>
var val = 100
function loadFile(url){
var s = document.createElement("script")
s.async = false
s.src = url
document.head.appendChild(s)
}
loadFile("test.js")
</script>
<script>for(var i=0;i<100000000;i++) i</script>
<script>for(var i=0;i<100000000;i++) i</script>
<script>for(var i=0;i<100000000;i++) i</script>
<script>for(var i=0;i<100000000;i++) i</script>
<script>for(var i=0;i<100000000;i++) i</script>
<script src="test2.js"></script>
test2.js を読み込む前に script タグを 5 つ用意してだいたい 1~2 秒かかります
この時間の間で test.js は読みこまれていて test2.js はまだ読みこまれていないのでいけるかな と思ったけど
100
loaded test
loaded test
だめでした
5
DOM を大量に挟んでみます[main.html]
<!doctype html>
<meta charset="utf-8">
<script>
var val = 100
function loadFile(url){
var s = document.createElement("script")
s.async = false
s.src = url
document.head.appendChild(s)
}
loadFile("test.js")
</script>
<div></div>
<!-- ↑の div を 一万個くらい -->
<script src="test2.js"></script>
<meta charset="utf-8">
<script>
var val = 100
function loadFile(url){
var s = document.createElement("script")
s.async = false
s.src = url
document.head.appendChild(s)
}
loadFile("test.js")
</script>
<div></div>
<!-- ↑の div を 一万個くらい -->
<script src="test2.js"></script>
すると
loaded test
200
200
なんと test.js を先に読みこんでくれています
原因がよくわからない・・・
6
2 のコードで loadFile のところで debugger で一時停止しますすると test2 はまだ DOM では作られていないのにすでに Network の一覧にありました
つまり DOM 構築前にパースは終わっていてリクエストは先に送っているみたいです
それでも DOM が多すぎると一度に全部パースはしないで区切ってるのか test2.js が先にリクエストしないことがあります
その場合は test.js が先にロードされて順番が変わるということだと思います
なんか複雑
とりあえず HTML に最初から書いているのと 動的に追加するものでロード順は決まらないので 動的なロードの後に 実行したいのなら非同期処理を考慮するように作るか 動的処理が絡むところ以降は全部動的にロードして async=false で順番制御がよさそうです
* これはあくまで Chrome での調査結果です