JavaScript 加载执行优化:从阻塞到无阻塞加载的演进

作者:巡夜人

时间:2026-10-28

浏览:493

本文深入探讨 JavaScript 文件的加载策略对页面性能的影响。从将脚本置于 body 底部以减少渲染阻塞,到合并文件以降低 HTTP 请求次数,再到利用动态脚本注入实现无阻塞加载。文章对比了不同场景下的执行顺序与兼容性处理,旨在提升网页加载速度与用户体验。

文章目录

从事前端开发一年多,积累了一些关于前端开发的见解,特此整理分享。

前端开发离不开各种工具的支持,例如我常用的 Google 浏览器以及用于抓包分析的 Fiddler。

原始情况与问题分析

一:原始情况

首先观察以下代码结构:

代码如下:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="JsLoad.Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="head">
 <title></title>
 <link href="Styles/Site.css" rel="stylesheet" type="text/css" />
 <script src="jquery/jquery-1.4.1.js" type="text/javascript"></script>
 <script src="js/hello.js" type="text/javascript"></script>
 <script src="js/world.js" type="text/javascript"></script>
</head>
<body>
 <img src="1.jpg" width="200" height="300" />
</body>
</html>

大约 90% 的开发者会将 JavaScript 文件放置在 head 标签内,但我们需要深入思考其后果。多数浏览器使用单线程同时处理“界面 UI 更新”和“JS 脚本执行”。

当解析器遇到 <script> 标签时,页面的下载和渲染过程必须暂停,直到该脚本执行完毕。这对用户而言体验极差,面对锁定的页面,

用户极有可能直接关闭页面。

原始情况与问题分析

通过上述瀑布图分析,我们可以发现两个关键点:

第一:

尽管三个 JS 文件并行下载,但根据前述理论,JS 脚本应串行执行。值得注意的是,IE8、Firefox3.5 和 Chrome2 均实现了 JS 的并行下载,

这是一个显著的进步,但它仍然会阻碍其他资源(如图片)的下载。

第二:

图片 1.jpg 的下载是在 JS 执行完成后才触发的,这证实了上述观点:JS 加载阻塞了图片资源的加载。

第一步优化:调整脚本位置

二:第一步优化

既然 JS 会阻塞 UI 渲染,我们可以尝试将 JS 文件移至 </body> 标签之前。这样可以确保 <script> 之前的 HTML 内容能够完整呈现,避免用户看到页面空白等待

的情况,从而提升页面的友好度。

代码如下:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="JsLoad.Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="head">
 <title></title>
 <link href="Styles/Site.css" rel="stylesheet" type="text/css" />
</head>
<body>
 <img src="1.jpg" width="200" height="300" />
 <script src="jquery/jquery-1.4.1.js" type="text/javascript"></script>
 <script src="js/hello.js" type="text/javascript"></script>
 <script src="js/world.js" type="text/javascript"></script>
</body>
</html>

下方的图表显示,1.jpg 和三个 JS 文件几乎可以并行下载和执行。总耗时由之前的“469ms+”缩短至“326ms”。

原始情况与问题分析

第二步优化:减少 HTTP 请求

三:第二步优化

观察上述“瀑布图”,可以发现三个 JS 文件触发了三次“Get”请求。众所周知,HTTP Get 请求需要携带 HTTP 头信息,

这必然消耗额外时间。因此,我们的优化方案是减少 Get 请求次数。通常有两种实现方式。

第一种:合并 JS 文件,例如将上述的“hello.js”和“world.js”合并为一个文件。

第二种:利用第三方工具,例如 PHP 中的 Minify。

关于第二种做法,淘宝应用较多。查看其中的一个 script 标签,它应用了三个 JS 文件,但由 3 个 Get 请求变为 1 个。

原始情况与问题分析

第三步优化:无阻塞加载策略

四:第三步优化

无论是将 JS 文件置于页面底部,还是将多个文件合并为一个,其本质仍属于“阻塞模式”,即锁定浏览器。随着 Web 页面日益复杂,JS 文件数量增多,

这依然令人头疼。因此,我们提倡采用“无阻塞模式”加载 JS 脚本,即在页面完全呈现后再追加 JS,这对应着在 window.onload 事件触发后,

再追加 JS。这就是所谓的“无阻塞”加载,但其中有一个非常关键的注意事项:我们需要明确对 JS 加载顺序是否有严格要求。

第一种情况:无顺序要求。例如,如果“hello.js”和“world.js”之间没有依赖关系,我们可以完全使用 jQuery 动态追加来实现。

代码如下:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="JsLoad.Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="head">
 <title></title>
 <link href="Styles/Site.css" rel="stylesheet" type="text/css" />
</head>
<body>
 <img src="1.jpg" width="200" height="300" />
 <script src="jquery/jquery-1.4.1.js" type="text/javascript">
 <script type="text/javascript">
 window.onload = function () {
 $("#head").append("<script src='js/hello.js' type='text/javascript'><\/script>")
 $("#head").append("<script src='js/world.js' type='text/javascript'><\/script>");
 }
 </script>
</body>
</html>

原始情况与问题分析

从图中可以看出,“hello.js”和“world.js”出现在蓝色线之后,说明这两个 JS 文件是在 DOMContentLoaded 结束后才触发加载的,这样就不会造成页面锁定

等待。

第二种情况:有顺序要求

为什么必须考虑顺序要求?对于上述动态追加的“两个 JS”文件,在 IE 系列浏览器中,无法保证 hello.js 一定在 world.js 之前执行,

它只会按照服务器端返回的顺序执行代码。

代码如下:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="JsLoad.Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="head">
 <title></title>
 <link href="Styles/Site.css" rel="stylesheet" type="text/css" />
</head>
<body>
 <img src="1.jpg" width="200" height="300" />
 <script type="text/javascript">
 function loadScript(url, callback) {
 var script = document.createElement("script");
 script.type = "text/javascript";
//IE
 if (script.readyState) {
 script.onreadystatechange = function () {
 if (script.readyState == "loaded" || script.readyState == "complete") {
 script.onreadystatechange = null;
 callback();
 }
 }
 } else {
 //非IE
 script.onload = function () {
 callback();
 }
 }
 script.src = url;
 document.getElementById("head").appendChild(script);
 }
 //第一步加载jquery类库
 loadScript("jquery/jquery-1.4.1.js", function () {
 //第二步加载hello.js
 loadScript("js/hello.js", function () {
 //第三步加载world.js
 loadScript("js/world.js", function () {
});
 });
 });
 </script>
</body>
</html>

原始情况与问题分析

大家也能看到,页面完全 Load 的时间其实也就 310ms 左右,大大提高了网页的下载呈现和友好型。

同样也可以看看腾讯网,他也是这么干的。

原始情况与问题分析

是不是非常的有用呢,本人这里也是花了些时日来做这些研究测试,希望小伙伴们能看到心里去,毕竟这也是“麻花藤”公司的解决方案,大家参考下吧

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章