若是你在控制檯看到了如下信息,那麼這篇文章對你而言應該會有幫助:javascript
(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.
對於如今的web的開發者而言,document.write
應該是入門級的DOM API,但實際項目開發中,卻不多使用。若是面試官問你爲何不去使用它,你會怎麼回答?java
不少人可能會說這個性能低,那麼爲何低呢?先看個例子:web
document.write('<script src="https://paul.kinlan.me/ad-inject.js"></script>');
在瀏覽器渲染頁面以前,會去根據HTML標籤解析DOM樹。若是解析器遇到了 <script>
標籤,則會中止DOM的解析,優先執行腳本。若是這個腳本動態插入了另外一個腳本,則解析器會等待另外一個腳本下載完成到執行完成,延後了頁面渲染的時間。面試
對於網絡環境差的,好比 2G
的用戶,經過 document.write
寫入的新的腳本,可能會致使頁面渲染的時間延後數十秒,用戶可能就所以放棄了繼續等待。基於Chrome的數據報告顯示,那些經過 document.write
插入第三方腳本的頁面在2G網絡下比通常頁面慢2倍。chrome
Chrome從55版本開始就開始選擇性的干預這類寫法,當同時知足如下條件的時候,會禁止腳本執行:瀏覽器
document.write
位於最高層級的document上(若是位於iframe中,由於不會阻止主頁面渲染,因此不會干預)document.write
中的腳本是解析阻塞型的(若是帶了 async
或者 defer
屬性,則不會干預)通常第三方庫會用這種寫法來加載腳本,不過慶幸的是,大部分第三方庫都支持async加載,這樣就不會阻塞剩餘內容的展示了。緩存
禁用 document.write
插入新的腳本便可,沒有比這更好的方案,若是必須使用,則加上 async
屬性。服務器
有6條之多的規則須要檢查,對你來講可能太過複雜,有沒有更好的方法去檢測?網絡
想要知道多少用戶受影響,只須要看看多少用戶是2G網絡,能夠使用 Network Information API 來檢測,而後將檢測結果發到統計系統或者RUM收集系統:異步
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. }
若是在使用 document.write
的時候,只知足了2-5的條件,你會看到下面這種提示:
在開發者工具中看到這個你能夠馬上發現問題,但怎麼去檢測這個影響範圍有多廣呢?你能夠檢測發往你服務器請求的HTTP Headers
你可能會嘗試着模擬2G網絡來強制干預,但其實不必,能夠直接開啓這項功能,使用 chrome://flags/#disallow-doc-written-script-loads
若是經過 document.write
的方式插入的腳本被阻止了,瀏覽器會攜帶這樣的請求頭去請求資源:
Intervention: <https://shorturl/relevant/spec>;
若是隻是warning,會攜帶如下請求頭:
Intervention: <https://shorturl/relevant/spec>; level="warning"
這些請求頭會攜帶在對資源的GET請求中(在實際干預的狀況下異步請求)
對於現代開發者而言是幸運的,由於大部分第三方庫的編寫者已經再也不使用 document.write
的方式插入腳本了,項目開發中咱們只要稍微留個心就好,一些遠古的第三方庫可能還會存在這樣的問題。