关于web:页面加载性能之禁用documentwrite

38次阅读

共计 2058 个字符,预计需要花费 6 分钟才能阅读完成。

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

(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…

正文完
 0