關於document.write()加載JS等靜態資源 和 異步async加載JS

現流行瀏覽器對於靜態資源的預加載

傳統的瀏覽器,對於靜態資源加載,會阻塞 HTML 解析器的線程進行,不管內聯仍是外鏈。
例如:html

<script src="test1.js"></script>
    <script src="test2.js"></script>
    <script src="test3.js"></script>
    <img src="img.png" />

傳統瀏覽器HTML解析器,會從test1.js 逐一解析到img.png,只個解析過程是同步的,只有當test1.js解析加載完成纔會到test2.js 順序加載。假設js文件加載時間須要1秒,img文件也須要1秒的時間,那麼除去頁面其餘階段的render時間不計,img圖片會是4秒以後才顯示給用戶。前端

然而,如今主流瀏覽器對於靜態資源的解析,已經作到了預解析和預加載。

相比傳統瀏覽器,當瀏覽器HTML解析器,遇到test1.js靜態資源的是,主線程中的解析器暫停解析,瀏覽器會新開啓一個解析器線程,去預加載後面的資源。假設js文件加載時間須要1秒,img文件也須要1秒的時間。當瀏覽器遇到第一個js文件test1.js的時候,會新開啓一個解析器線程,去預加載解析其餘靜態資源。除去頁面其餘階段的render時間不計,那麼img圖片只會是2秒以後才顯示給用戶。瀏覽器

但瀏覽器能作的僅僅是預解析和預加載,腳本的執行和 DOM 樹的構建仍然必須是線性的緩存

document.write() 打破瀏覽器的預解析和預加載,由於document.write()加載的JS文件沒法讓HTML預解析器發現

<script src="test1.js"></script>
    <script>
        document.write('<script src="http://xxx.com/test2.js"><\/script>')
    </script>
    <script src="test3.js"></script>

這個例子中,因爲 test2.js 是經過 JS 代碼插入的,HTML 預解析器是看不到的,因此只有當 test1.js 下載並執行完畢,且第二個內聯的 script 執行完畢後,test2.js 纔會開始下載,也就是說,test2.js 不能和 test1.js 及 test3.js 並行下載了,從而致使頁面展示變慢,一樣假設每一個文件的下載時間都是 1 秒,那麼這三個文件下載執行完就須要兩秒,就由於 test2.js 不能預加載。在一個外鏈的 JS 文件好比 a.js 中執行 document.write("<script...) 也是相似的效果。異步

針對document.write() 去加載靜態資源,咱們能夠作出什麼優化?

將資源轉成外鏈的方式加載。
以下async

<script src="test1.js"></script>
    <script>
        document.write('<script src="http://xxx.com/test2.js"><\/script>')
    </script>
    <script src="test3.js"></script>

改爲優化

<script src="test1.js"></script>
    <script src="test2.js"></script>
    <script src="test3.js"></script>

儘量,讓瀏覽器預解析器發現靜態資源文件。可是這並不意味着頁面的加載時間會大大減小。
假設test1.js的加載時間爲1秒,test2.js的加載時間爲10秒。即使test1.js以後的靜態資源參與了瀏覽器的預解析加載,爲了配合這句話「但瀏覽器能作的僅僅是預解析和預加載,腳本的執行和 DOM 樹的構建仍然必須是線性的」。頁面始終會所有資源加載完以後才完成渲染,test2.js的10秒加載時間仍舊會讓頁面處於loading轉圈狀態。spa

對於非第三方的靜態資源的加載時間太長,應考慮前端資源的優化,這裏列出來可能多的優化方案,可是暫不作詳解線程

  • 減小靜態文件的文件大小 (代碼壓縮)
  • 減小靜態文件請求數量 (文件合併)
  • gzip
  • CDN和緩存

對於第三方的靜態資源文件,可使用async實現異步加載code

async 加載靜態資源

一句話歸納即是異步的 script 根本不會阻塞 HTML 解析器,也就用不到預解析了
目前大部分第三方庫都會支持async 異步 加載JS資源,而後去調用一個全局function 例如

<script src="test.js?callback=dosomething" async ></script>

async 的js資源,若是長時間pedding 會影響onload加載時間

關於document.write()的其餘知識點

ducument.write 在onload以前,插入執行document.write()都會給頁面插入內容,頁面onload完成以後,瀏覽器輸出流自動關閉;在此以後,任何一個對當前頁面進行操做的document.write()方法將打開—個新的輸出流

以下

結果是:

頁面onload完成以後,調用document.write

結果是:

相關文章
相關標籤/搜索