去掉你代码里的 document.write(“<script...)

本文探讨了使用`document.write`加载脚本如何影响网页性能,包括阻塞HTML解析、预加载和预解析的问题。浏览器在遇到`document.write`时可能需要重新解析HTML,导致页面加载变慢。Chrome的工程师发现此问题尤其常见于广告和统计脚本,并计划逐步采取措施屏蔽这些脚本。最佳实践是改用异步加载脚本,以提高页面加载速度和用户体验。
摘要由CSDN通过智能技术生成

在传统的浏览器中,同步的 script 标签是会阻塞 HTML 解析器的,无论是内联的还是外链的,比如:

<script src="a.js"></script>
<script src="b.js"></script>
<script src="c.js"></script>
<img src="a.jpg">

在这个例子中,HTML 解析器会先解析到第一个 script 标签,然后暂停解析,转而去下载 a.js,下载完后开始执行,执行完后,才会继续解析、下载、执行后面的两个 script 标签,最后解析那个 img 标签,下载图片,展现图片。假设每个文件的下载时间都是 1 秒,且忽略浏览器的执行耗时,那么你最终会在第 4 秒结束时看到 a.jpg 渲染在了浏览器上。

如今的浏览器已经不再这么线性的执行了,在遇到第一个 script 标签后,主线程中的解析器暂停解析,但浏览器会开启一个新的线程去于预解析后面的 HTML 源码,同时预加载遇到的CSS、JS、图片等资源文件,也就是说,在现代浏览器中,上面这个例子中的四个资源文件是会被并行下载的,所以不考虑浏览器的执行耗时的话,渲染出最后那张图片只需要 1 秒钟。

额外小知识:

但浏览器能做的仅仅是预解析和预加载,脚本的执行和 DOM 树的构建仍然必须是线性的,从而页面的渲染也必须是线性的。脚本必须顺序执行这很好理解,比如 b.js 很可能用到 a.js 里的变量;DOM 树不能提前构建的原因也能想到,a.js 里很可能去查询 DOM 树,在那时执行 querySelectorAll("script").length 必须是 1,img 的话必须是 0。

但还有一个东西也能解释上面两个优化不能做的原因,甚至也能让预解析和预加载这两个已经做了的优化失效的东西,那就是 document.write(),document.write 可以在当前执行的 script 标签之后插入任意的 HTML 源码,如果你插入一个 "<div>foo</div>" 那还好,但如果插入一个未闭合的开标签呢,比如:

<script>
document.write("<textarea>") // 还可以是 document.write("<!--") 等
</script>
<script src="a.js"></script>
<script src="b.js"></script>
<script src="c.js"></script>
<img src="a.jpg">

当第 1 个 script 标签执行完毕后,浏览器就会发现,因为 document.write 输出了一个未闭合的开标签,所以刚才做的预解析成果得全部扔掉,重新解析一次,第二次解析后 script 标签和 img 标签都成了 textarea 的内容了,因此预加载的 JS 和图片资源都白加载了。但这种情况毕竟是少数,预解析的利远远大于弊,所以浏览器们才做了这个优化,MDN 上有一篇文章列举了一些会让浏览器做的预解析优化失失效的代码

本文的主角是用 document.write 输出一个 script 标签的情况,比如:

<script src="a.js"></script>
<script>
document.write('<script src="http://thirdparty.com/b.js"><\/script>')
</script>
<script src="c.js"></script>

这个例子中,由于 b.js 是通过 JS 代码插入的,HTML 预解析器是看不到的,所以只有当 a.js 下载并执行完毕,且第二个内联的 script 执行完毕后,b.js 才会开始下载,也就是说,b.js 不能和 a.js 及 c.js 并行下载

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhuhaiuser

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值