[JavaScript] 檢查 DOM 載入狀態 Document.readyState
有點經驗的前端工程師都知道需要使用 window.onload
、 addEventListener('load')
或是 jQuery 的 $(document).ready()
來確定 DOM 載入完成, 用來確保 JavaScript 不會因為找不到 DOM , 而導致程式無法運行
不過只是單單使用上面的監聽方式是不夠的,這邊分享一下實際踩雷的經驗
當今天有使用者使用你開發的套件的時候,他不一定會在一開始就會載入你開發的套件
用下面的代碼來解釋:
game.js
const run = () => {
const startGame = document.createTextNode('活動開始嘍~')
document.body.appendChild(startGame)
}
document.addEventListener('load', function() {
run()
})
index.html
<body>
<head>
<meta charset="utf-8">
<title>活動首頁</title>
</head>
<script>
const script = document.createElement('script')
script.setAttribute('type', 'text/javascript')
script.setAttribute('src', './js/game.js')
const head = document.getElementsByTagName('head')[0]
setTimeout(function(){
head.appendChild(script)
}, 1000 * 60)
</script>
</body>
小弟碰到的就是上方的情境,當使用者在觀看某個頁面時,會在特定的時間中,才去執行遊戲
上面的範例為載入頁面後,60 秒才去執行遊戲
但在 60 秒後,你會發現 function 並沒有被執行,這是因為在 game.js 中,我們是在 window.load 的底下,調用 run()
函式
但是在等待的這 60 秒的期間, doucment 已經載入完成,並 已經調用過 window.load 的 Hook 過了
也就是說,我們在 window.onload 後,再去監聽 window.onload 時是沒有意義的, run() 並不會執行
Document.readyState
但因為我們開發套件,必須要確保程式碼是在任何情況都能調用的
查看以下文件後,發現 Document 底下有著 readyState
的屬性
Document.readyState
可以回傳 Document 載入的狀態,如下方代碼表示:
switch (document.readyState) {
case "loading":
// 文件讀取中。
break;
case "interactive":
// 文件已經完成讀取。可以使用 DOM 元素。
var span = document.createElement("span");
span.textContent = "A <span> element.";
document.body.appendChild(span);
break;
case "complete":
// 頁面已經完成讀取。
console.log("The first CSS rule is: " + document.styleSheets[0].cssRules[0].cssText);
break;
}
MDN: Document.readyState
再來我們可以使用 Document.readyState
來進行實作了,寫了一個 function 如下:
const readyLoad = callback => {
if(Document.readyState === 'complete'){
callback()
} else{
document.addEventListener('load', function() {
callback()
})
}
}
readyLoad(run) // 調用 run
這樣就可以確保在上述情境下,程式碼是可以被運行的了