[JavaScript] 檢查 DOM 載入狀態 Document.readyState

有點經驗的前端工程師都知道需要使用 window.onloadaddEventListener('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

這樣就可以確保在上述情境下,程式碼是可以被運行的了

Facebook 功能: