如果你在控制台看到了以下信息,那么这篇文章对你而言应该会有帮忙:

(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,但理论我的项目开发中,却很少应用。如果面试官问你为什么不去应用它,你会怎么答复?

很多人可能会说这个性能低,那么为什么低呢?先看个例子:

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从55版本开始就开始选择性的干涉这类写法,当同时满足以下条件的时候,会禁止脚本执行:

  1. 用户处于低速网络下,比方2G(今后可能会把该条件扩大成3G以及低速wifi)
  2. document.write 位于最高层级的document上(如果位于iframe中,因为不会阻止主页面渲染,所以不会干涉)
  3. document.write 中的脚本是解析阻塞型的(如果带了 async 或者 defer 属性,则不会干涉)
  4. 脚本与页面不在同一个站点下,Chrome不会干涉eTLD+1级别的脚本,如: js.example.com 和 www.example.com
  5. 脚本不在HTTP Cache中,如果在缓存中,仍然会执行,因为不会收回HTTP申请
  6. 页面的申请不是重载。如果用户手动从新重载,Chrome还是会执行脚本

个别第三方库会用这种写法来加载脚本,不过庆幸的是,大部分第三方库都反对async加载,这样就不会阻塞残余内容的展示了。

如何修复这类问题?

禁用 document.write 插入新的脚本即可,没有比这更好的计划,如果必须应用,则加上 async 属性。

当你的站点受影响之后,如何检测?

有6条之多的规定须要查看,对你来说可能太过简单,有没有更好的办法去检测?

检测用户是不是2G网络

想要晓得多少用户受影响,只须要看看多少用户是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

查看你的资源申请的HTTP headers

如果通过 document.write 的形式插入的脚本被阻止了,浏览器会携带这样的申请头去申请资源:

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

如果只是warning,会携带以下申请头:

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

这些申请头会携带在对资源的GET申请中(在理论干涉的状况下异步申请)

总结

对于古代开发者而言是侥幸的,因为大部分第三方库的编写者曾经不再应用 document.write 的形式插入脚本了,我的项目开发中咱们只有略微留个心就好,一些远古的第三方库可能还会存在这样的问题。

参考

  • https://developers.google.com...
  • https://web.dev/no-document-w...
  • https://developers.google.com...