如果你在控制台看到了以下信息,那么这篇文章对你而言应该会有帮忙:
(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 版本开始就开始选择性的干涉这类写法,当同时满足以下条件的时候,会禁止脚本执行:
- 用户处于低速网络下,比方 2G(今后可能会把该条件扩大成 3G 以及低速 wifi)
document.write
位于最高层级的 document 上(如果位于 iframe 中,因为不会阻止主页面渲染,所以不会干涉)document.write
中的脚本是解析阻塞型的(如果带了async
或者defer
属性,则不会干涉)- 脚本与页面不在同一个站点下,Chrome 不会干涉 eTLD+ 1 级别的脚本,如: js.example.com 和 www.example.com
- 脚本不在 HTTP Cache 中,如果在缓存中,仍然会执行,因为不会收回 HTTP 申请
- 页面的申请不是重载。如果用户手动从新重载,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…