执行javascript
的代码会阻塞其他文件的下载
<script>
标签每次出现都会霸道地让页面等待脚本的解析和执行,无论当前的javascript
代码是内嵌还是包含在外链文件中,页面的下载和渲染都会停下来等待脚本执行完成。
例如:
<html>
<head>
<title>Script Example</title>
<script type="text/javascript" src="file1.js"></script>
<script type="text/javascript" src="file2.js"></script>
<script type="text/javascript" src="file3.js"></script>
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<body>
<p>Hello world!</p>
</body>
</html>
这些看似正常的代码实际上有十分严重的性能问题:在<head>
中加载三个javascript
文件。由于脚本会阻塞页面渲染,直到它们全部下载并执行完成后,页面的渲染才会继续。可以看下执行过程中的瀑布图:
由于脚本会阻塞页面其他资源的下载,因此推荐将所有的<script>
标签尽可能放到body
标签底部,即</body>
上面。
动态脚本元素
用标准的DOM
方法可以很容易的创建一个新的script
元素:
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = "file1.js";
document.getElementByTagName("head")[0].appendChild("script");
这个新创建的script
元素加载了file1.js
文件。文件在该元素被添加到页面时开始下载。这种技术的重点在于:无论在何时启动,文件的下载和执行过程都不会阻塞页面其他进程。甚至可以将代码放到<head>
区域不会影响页面其他部分。
推荐的无阻塞模式:
<script type="text/javascript" src="loader.js"></script>
<script type="text/javascript">
loadScript("the-rest.js",function() {
Application.init();
});
</script>
把这段代码放到</body>
闭合标签之前。另一种方法是将loadScript()
函数直接嵌入页面,从而避免多产生一次HTTP
请求。例如:
<script type="text/javascript">
function loadScript(url,callback) {
var script = document.createElement("script");
script.type = "text/javascript";
if(script.readyState) { // IE 这种基本不需要考虑了,ie 的份额很低,基本淘汰了
script.onreadystatechange = function() {
if (script.readyState == "loaded" || cript.readyState == "complete") {
script.onreadystatechange = null;
callback();
}
}
}else { // 其他浏览器
script.onload = function() {
callback();
}
}
script.src = url;
document.getElementByTagName("head")[0].appendChild("script");
}
loadScript("the-rest.js",function(){
Application.init();
})
</script>
优化建议
-
</body>
闭合标签前,将所有的<script>
标签放到页面底部。这能确保在脚本执行前页面已经完成了渲染。 -
合并脚本。页面中的
<script>
标签越少,加载也就越快,响应也更迅速。无论外链文件还是内嵌脚本都是如此。 -
有多种无阻塞下载
JavaScript
的方法:1、使用
script
标签的defer
或async
属性,这两者的相同点是采用并行下载,在下载的过程中不会产生阻塞。区别在于执行时机,async
是加载完后自动执行,而defer
需要等待页面完成后执行。
2、使用动态创建的<script>
元素来下载并执行代码。
3、使用XHR
对象下载javascript
代码并注入页面中。