爲何要避免使用 "document.write()"

本文是技術圈 google 瀏覽器前端新特性播報的推送,歡迎你們加入html

爲何要避免使用 document.write()

最近咱們發現若是咱們在頁面中使用了document.wirte(),那麼在 chrome 的開發者控制檯會出現下面的警告信息前端

(index):34 A Parser-blocking, cross-origin script, 
https://paul.kinlan.me/ad-inject.js, is invoked via document.write(). 
This may be blocked by the browser if the device has poor network connectivity.

爲啥要作這個提示呢,對於在2G,3G 或者是慢 wifi 環境下面,使用document.write()動態加載資源會讓頁面的展示慢10秒以上,瀏覽器能夠呈現頁面以前,必須經過解析HTML標記來構建DOM樹。每當解析器遇到腳本時,它必須中止並執行它,而後才能繼續解析HTML。若是腳本動態地注入另外一個腳本,解析器將被迫等待更長時間才能下載資源,這可能會致使一個或多個網絡往返並延遲首次渲染頁面的時間,致使頁面沒法加載或花費的時間長於用戶放棄。根據Chrome中的設備,咱們瞭解到,經過第三方腳本插入的document.write()頁面的速度一般比2G的其餘頁面載入速度慢兩倍。chrome

去除document.write的效果

chrome 開發者收集了28天chrome瀏覽器使用者的2G瀏覽數據,從中發現7.6%的2G加載頁面中都包含了經過document.write()寫入頁面的跨網站,而且會中斷瀏覽器解析的腳本。經過把這些加載腳本進行攔截加載,咱們看到了如下的改進:segmentfault

  • 頁面加載到達first contentful paint(視覺上讓用戶感受正在加載的狀態)t的狀態的數量增長10%,達到徹底解析狀態的頁面數量增長25%,減小10%因爲須要刷新頁面帶來的用戶失望
  • 到達first contentful paint的時間減小了21%(加快速度大於1秒)
  • 解析頁面所需的時間減小了38%,差很少加快了6秒,大大減小了向用戶展現內容的時間

chrome 瀏覽器對於document.write的策略

針對以上的測試數據,chrome 從 55版本開始,chrome 瀏覽器對用戶使用的document.write()進行干預,若是符合如下全部的狀況,頁面<script>標籤中的document.write()將不會被執行:api

  1. 用戶處於緩慢的鏈接狀態,特別是用戶在2G時。(未來可能會延伸到慢速鏈接的其餘用戶,例如慢速3G或慢速WiFi。)
  2. document.write()在一個頂級的文件中,不適用於iframe中的document.write腳本,由於它們不會阻止主頁面的呈現。
    3.document.write()中加載的腳本是會阻斷解析的,若是腳本中有async或者是defer屬性,那麼它們仍是會被解析執行

4.document.write()中加載的腳本和頁面地址不是同個主域的,換句話說,chrome 瀏覽器不會阻止script標籤符合eTLD+1規則的加載(好比頁面地址是www.a.com,script的地址是 js.a.com
5.document.write()中加載的腳本還沒有在瀏覽器HTTP緩存中。緩存中的腳本不會致使網絡延遲,而且仍然會執行。瀏覽器

  1. 頁面的請求不是從新加載。若是用戶觸發從新加載而且正常執行該頁面,Chrome將不會進行干預。

如何檢測你的document.write是否被執行限制了

chrome 提供了多種方式來檢測你的document.write請求是否被限制了緩存

瞭解下你的用戶在2G下面的使用佔比

因爲上面的規則現階段只針對慢速狀況2G,所以首先能夠先分析出來,你的網站的2G 用戶佔比,經過chrome提供的網絡信息 API,能夠判斷用戶是否是在2G 環境下面,代碼以下網絡

if(navigator.connection &&
   navigator.connection.type === 'cellular' &&
   navigator.connection.downlinkMax <= 0.115) {
   // Notify your service to indicate that you might be affected by this restriction.
}

在 Chrome DevTools 中捕獲警告

chrome devtools中,若是頁面知足上面的2-5的規則,則會在chrome devtools中看到以下警告
clipboard.pngapp

異步

更加全面的告警

上面兩種方式結合以後能夠對影響的用戶量有一個初步的判斷,若是要作精確的判斷,能夠檢查 HTTP 頭部:
當插入的腳本document.write被阻止時,Chrome會將如下標頭髮送到所請求的資源:

Intervention: <https://shorturl/relevant/spec>;

當document.write發現插入腳本時,可能會在不一樣狀況下被阻止,Chrome可能會發送:

Intervention: <https://shorturl/relevant/spec>; level="warning"

干預頭將做爲腳本的GET請求的一部分發送(在實際干預的狀況下異步)。

替換方案

因爲document.write會減慢頁面的加載,能夠考慮使用appendChild等 api 將元素插入頁面中,不過這二者有如下的區別

  • document.write的參數是一個 html 字符串,appendChild是一個Node對象
  • 若是有多個document.write寫入 script 標籤,標籤與標籤之間的加載是同步的,也就是說,標籤的加載順序會和document.write的執行順序相同;而使用appendChild插入多個sciprt標籤時,標籤加載的順序是不肯定的,先加載完成的先執行,所以經過appendChild插入script標籤時,要注意是否須要對加載的順序進行控制,能夠經過script.onload進行順序回調插入
相關文章
相關標籤/搜索