JavaScript 加载顺序与执行原理:从阻塞到无阻塞优化
本文深入解析 JavaScript 在浏览器中的加载与执行机制,重点探讨脚本对页面渲染的阻塞问题。通过对比传统放置方式与底部加载、脚本合并、defer 属性及动态脚本注入等无阻塞技术,提供提升 Web 应用性能的具体策略与代码实现建议。
JavaScript 加载与执行原理概述
前言
JavaScript 在浏览器中的性能表现,往往是开发者面临的最严峻的可用性挑战之一。本文基于《高性能 JavaScript》中关于加载和执行章节的内容,深入探讨如何解决 JavaScript 的加载顺序问题及其底层执行原理。

当浏览器解析到 <script> 标签时,必须优先下载外部引用的 JS 文件并立即执行。在此过程中,页面的渲染和用户交互会被完全阻塞,直到脚本处理完毕。
脚本放置位置对性能的影响
脚本放置位置的影响

这种机制存在显著的性能隐患。由于脚本执行会阻塞页面渲染,浏览器必须等待所有脚本下载并执行完成后,才能继续渲染页面。下图展示了典型的代码执行顺序:

浏览器会先下载第一个 JS 文件,只有在该文件完全下载并执行后,才会开始下载第二个 JS 文件。尽管现代浏览器如 IE8、Firefox 3.5、Safari 4 和 Chrome 2 已支持 JS 文件的并行下载,但 JS 文件的下载过程仍会阻塞图片等其他资源的加载。
因此,提升性能的有效方法之一是将脚本标签放置在 body 标签的底部。

脚本组织与合并策略
脚本组织策略
由于每个 <script> 标签在下载时都会阻塞页面渲染,减少页面中 <script> 标签的数量至关重要。解决方案是将多个 JS 文件合并打包为一个文件。这样做不仅能最小化延迟时间,显著改善页面整体性能,还能减少 HTTP 请求次数。
通常情况下,下载单个 100KB 的文件比下载 4 个 25KB 的文件速度更快。
如果页面包含多个外链 JS 文件,建议将它们合并为一个单一的 JS 文件。

无阻塞加载技术详解
无阻塞脚本技术
虽然下载单个较大的 JS 文件仅产生一次 HTTP 请求,但这会导致浏览器假死一段时间。为避免这种情况,需要采用逐步加载 JS 文件的技术。
defer 属性机制
延迟脚本(defer 属性)
defer 属性指示浏览器可以延迟执行脚本,但该特性仅支持 IE4+ 和 Firefox 3.5+ 等较新版本的浏览器。

简单来说,defer 机制确保在 DOM 加载完成前不会下载 JS 文件,从而避免阻塞浏览器的其他进程。

在不支持 defer 属性的浏览器中,事件触发顺序为:defer、script、load。
在支持 defer 属性的浏览器中,事件触发顺序为:script、defer、load。
因此,defer 脚本会在 onload 事件触发之前被调用。
动态脚本注入方法
动态脚本注入
动态脚本注入主要有两种方式:一是动态创建 script 标签,二是通过 XMLHttpRequest 注入页面。
首先介绍第一种方法的使用方式:

该技术的关键在于,无论何时启动下载,文件的下载和执行过程都不会阻塞页面的其他进程。但需要注意的是,使用动态脚本节点下载 JS 文件时,返回的代码会立即执行(Firefox 和 Opera 除外,它们会等待此前所有动态脚本节点执行完毕)。
主流浏览器在 <script> 标签接收完成时会触发一个 load 事件,但 IE 浏览器不支持此事件。因此,我们需要封装一个兼容所有浏览器的方法。

这种方式的缺点在于需要明确文件的加载顺序。当 JS 文件增多且依赖关系复杂时,管理加载依赖顺序变得非常困难。

例如,如下形式的代码很难维护:
第二种动态创建脚本的方式

这实际上相当于创建一个带有内联脚本的 <script> 标签。一旦新创建的 <script> 元素被添加到页面,代码就会立即执行并准备就绪。
其优点在于下载的 JS 代码不会立即执行,从而可以将脚本的执行推迟到准备好的时候。此外,这种方法兼容所有浏览器。
其缺点在于 JS 文件必须与所请求的页面处于相同的域,无法从 CDN 下载。因此,一般大型 Web 应用较少使用这种方式。
推荐使用无阻塞模式:
先添加动态所需的代码,然后假装初始化页面的剩余代码。
[图片上传失败...(image-dd3f9-1515902024710)]
上文介绍了多种技术,这里推荐一些动态延迟加载的库。
包括 YUI3、LazyLoad 和 LABjs 等库。个人觉得 LABjs 库较为好用,尽管本人未实际使用,建议大家去了解一下,具体使用方法此处不再赘述。
性能优化总结与建议
总结:
提高 JS 性能的几个关键方面
1. 在 </body> 闭合标签之前,将所有 <script> 标签放置在页面底部。这能确保在脚本执行前页面已完成渲染。
2. 合并脚本。页面中的 <script> 标签越少,加载速度越快,响应也越迅速。无论是外链文件还是内嵌脚本,均适用此原则。
3. 采用多种无阻塞下载 JS 的方法:
3.1 使用 <script> 标签的 defer 属性。
3.2 使用动态创建的 <script> 元素来下载并执行代码。
3.3 使用 XHR 对象下载 JS 代码并注入页面。
通过上述策略,可以极大提高那些需要使用大量 JS 的 Web 应用的实际性能。
以上就是本文的全部内容,希望本文的内容对大家的学习或工作具有一定的参考学习价值。如果有疑问,欢迎留言交流,感谢大家对本站的支持。
配置 Matter.js 睡眠机制以优化静止物体性能
2026-11-05 15:43:12
JavaScript console.log高级用法:用table、group和time优化调试输出
2026-11-05 08:04:56
JS变量中存储HTML代码时的特殊字符转义方法
2026-11-04 19:04:09
JS怎么安全转换带千分位或货币符号的字符串为数字
2026-11-04 11:54:14
推荐几款稳定的在线JS反混淆工具,支持Obfuscator.io解密
2026-11-04 08:16:21








