Html 的生命週期

零、序言

  vue 用多了,自然離不開生命週期。最近突發奇想,加上之前看過的文章中關於 script 標籤中的 async 和 defer 的搗糨糊,決定整理一下,攻克這個模糊點。

  當然,最多的還是與 script 標籤相關的前兩個週期,後倆個週期並沒有過多的複雜點,因此會着重描述前兩個。

 

  參考文章:

    1.頁面生命週期

    2.HTML,javascript,image等加載,DOM解析,js執行生命週期

 

一、頁面週期

  1.DOMContentLoaded - 瀏覽器已經加載了 Html, DOM 樹已經構建完畢,但是 img 和外部樣式表等資源可能還沒有下載完畢。

  2.load - 瀏覽器已經完全加載了所有資源。

  3.beforeunload - 用戶即將離開頁面。

  4.unload - 用戶離開頁面。

 

  每一個事件都有特定的用途,前兩個如其名,beforeunload 會給用戶彈出個確認框,unload 則不會。

 

二、DOMContentLoaded

  DOMContentLoaded 事件由 document 對象觸發,我們可以使用 addEventListener 來觸發。

  正如前文所說,在這個事件觸發的時候,我們如果獲取某些 img 的寬度和高度的話,得到的可能是0。

  當然這裏是有陷阱的。

 

  1. 與腳本(<script />)

    首先有一點,瀏覽器的 UI 渲染線程和 JS 引擎是互斥的,當 JS 引擎執行時 UI 線程會被掛起。因此,當瀏覽器在解析 HTML 時遇到 <script /> 時,將不會繼續構建 DOM 樹,轉而取解析、執行腳本,所以 DOMContentLoaded 有可能在所有腳本執行完畢之後觸發。

    外部腳本(通過 src  引入)的加載和解析和自帶的一樣會暫停 DOM 樹的構建,這裏  DOMContentLoaded 會等待。

    不過有兩個特殊的情況,如果外部腳本上帶有 async 或者 defer 屬性,那麼瀏覽器會繼續執行 DOM 解析而不需要等待腳本的完全執行,所以這一直時外部腳本的優化方案之一。(async 和 defer 屬性僅對外部腳本起作用, 當 src 不存在的時候會被自動忽略)

    關於 async 和 defer 與 DOM 的解析順序如下圖所示:

 

    既然提到了 async 和 defer,  也順帶整理一下他們的異同:

  async defer
順序 帶有 async 的腳本是優先執行先加載完的腳本,即他們在頁面中的順序並不保證他們的執行順序。 帶有 defer 的腳本時按照他們在頁面中出現的順序依次執行。
DOMContentLoaded 帶有async的腳本也許會在頁面沒有完全下載完之前就加載,這種情況會在腳本很小或本緩存,並且頁面很大的情況下發生。 帶有defer的腳本會在頁面加載和解析完畢後執行,剛好在 DOMContentLoaded之前執行。

 

    所以 async 用在完全沒有依賴和被依賴的腳本上。

 

三、load

  load 事件是在 window 對象上的,這與 DOMContentLoaded 不同。該事件在所有文件包括樣式表,圖片和其他資源下載完畢後觸發。既然這樣規定,自然該幹啥幹啥,沒什麼明顯的陷阱。

 

四、beforeunload

  如果用戶即將離開頁面或關閉窗口時,beforeunload 事件將會被觸發以進行額外的確認。舉個例子:

window.onbeforeunload = function() {
  return "There are unsaved changes. Leave now?";
};

  當然,如果在 chrome 和 firefox 瀏覽器中會忽略返回的自定義的字符串,這是出於安全考慮的。

 

五、unload

  unload 事件與 load 事件一樣,是在 window 對象上的,觸發時間爲用戶關閉該頁面的時候,我們可以做一些不存在延時的任務,比如關閉彈層等等。

 

六、readyState

  document.readyState 這個只讀屬性可以告訴程序當前文檔加載到哪一個步驟,它有三個值:

    1. loading - 加載,document 仍在加載中;

    2. interactive - 互動,文檔已經完成加載,文檔已被解析,但是諸如圖像,樣式表和框架之類的子資源仍在加載。

    3. complete - 文檔和所有子資源已完成加載。狀態表示 load 事件即將被觸發。

  而這個屬性的每次改變同樣有一個事件可以監聽:

document.addEventListener('readystatechange', () => console.log(document.readyState));

   不過這個 change 事件很少會被用到,可能出現的地方在某些第三方類庫中判斷一些依賴關係等地方。不詳述,具體可移步文首的文章或者 MDN。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章