这几天分享一下我看《高性能 JavaScript》的学习笔记,希望能对大家有所帮助。
为什么加载和执行顺序会影响性能?
多数浏览器使用单一进程来处理用户界面刷新和 JavaScript 脚本执行,同一时间只能做一件事。脚本会阻塞页面渲染,直到脚本被下载并执行完成后,页面渲染才会继续。
优化一:<script> 标签置于最后
将 <script> 脚本放在 <body> 底部最后下载,让页面其他部分先下载完成。这样大部分的页面就已经显示给了用户,而且脚本执行行为也不会过多的影响页面显示。
优化二:减少 <script> 标签数量
由于每个 <script> 标签初始下载时都会阻塞页面渲染,所以要减少 <script> 标签的数量。书上提到可以使用合并处理器将多个 URL 合并为一个以减少 <script> 数量。
优化三:无阻塞脚本
- 如果脚本本身不会修改 DOM,可以加上 defer 安全延时执行脚本。这样就不会阻塞浏览器其他进程,且带有 defer 的 <script> 标签在 DOM 完成加载之前都不会被执行。
- 可以动态创建 <script> 标签元素来获取脚本,这种下载和执行脚本的方式不会阻塞页面其他进程。
var script = document.createElement("script");
script.type = "text/javascirpt";
script.src = "file1.js";
document.getElementByTagName("head")[0].appendChild(script);
- 使用 XHR (ajax)获取脚本动态创建 <script> 脚本。逻辑和上面的差不多,只不过获取脚本方式有所不同。不过需要注意避免跨域问题。
- 书上推荐的无阻塞模式:1. 加载尽量少且必须的 js 代码。2. 动态获取其他脚本代码。下面的代码中只获取了必要的 loader.js 脚本,再动态获取了 test.js 脚本。
<body>
...
<script type="text/javascript" src="loader.js"></script>
<script type="text/javascript">
loadScript('test.js', function(){
Application.init();
})
</script>
<body/>
- YUI3 方案:1. 添加种子代码。2. 使用特定功能时通过拼接 URL 获取代码,实现功能。
- LazyLoad 类库:一种延时加载工具,减少不必要的初始化加载。
- LABjs 也是一种无阻塞脚本加载工具,它可以更加精细地控制整个加载过程。
小结
由于单一进程特性,在浏览器解析 HTML 代码过程中,遇到 <script> 标签会被阻塞,等到脚本下载并执行完成后在继续解析下面的代码。所以,为了避免页面解析时间过长的性能问题。提出了下面 3 类方案:
- 将 <script> 放在 <body> 底部,先解析页面后下载和执行脚本。
- 合并 URL 链接以减少 <script> 数量,避免反复下载和执行带来的时间损耗。
- 立即执行必要的脚本,延时执行脚本。
最后
本文完全参考《高性能 JavaScript》一书,如果问题欢迎留言交流。









网友评论