iframe异步加载_页面加载性能之禁用document.write

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

(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级别的脚本,如: http://js.example.com 和 http://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的条件,你会看到下面这种提示:

ac9f23c9469ccf03ce58055cd6de7128.png

在开发者工具中看到这个你可以立刻发现问题,但怎么去检测这个影响范围有多广呢?你可以检测发往你服务器请求的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/web/updates/2016/08/removing-document-write
  • https://web.dev/no-document-write/
  • https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/loading-third-party-javascript
异步加载iframe是一种在页面加载过程中,通过延迟加载iframe内容的方法,以提高页面性能和用户体验。一种常见的异步加载iframe的方法是使用JavaScript的setTimeout()函数来延时加载iframe的内容。在代码中,我们可以使用setTimeout()函数来延迟执行设置iframe的src属性的函数,以便在页面加载完成后再加载iframe的内容。这种方法可以避免阻塞主页面加载,并提高页面加载速度。另外,还有一种友好iframe(friendly iframe)技术,它也是一种无阻塞加载的方法,不过它可能不算是iframe加载的技术,但是必须使用iframe。 下面是一个示例代码,演示了如何使用setTimeout()函数来实现异步加载iframe: <iframe id="iframe1" src="" width="200" height="100" border="2"></iframe> <script> function setIframeSrc() { var s = "path/to/file"; var iframe1 = document.getElementById('iframe1'); if (-1 == navigator.userAgent.indexOf("MSIE")) { iframe1.src = s; } else { iframe1.location = s; } } setTimeout(setIframeSrc, 5); </script> 在这个示例中,我们使用了setTimeout()函数将setIframeSrc函数延迟执行了5毫秒,以便在页面加载完成后再加载iframe的内容。当setTimeout()函数执行后,setIframeSrc函数会根据浏览器类型设置iframe的src属性或location属性来加载指定的文件。这样就实现了异步加载iframe的效果。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [iframe异步加载技术及性能](https://blog.csdn.net/shadow_zed/article/details/86682331)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值