脚本加载
js脚本会阻塞页面其他资源的下载,直到其下载、解析、执行完毕。因为浏览器需要1个稳定的DOM树结构,而JS中很有可能有代码直接改变了DOM树结构,比如使用 document.write 或 appendChild,甚至是直接使用的location.href进行跳转,浏览器为了防止出现JS修改DOM树,需要重新构建DOM树的情况,所以 就会阻塞其他的下载和呈现.
html、css、图片是可以并行加载的。当浏览器从服务器接收到了HTML文档,并把HTML在内存中转换成DOM树,在转换的过程中如果发现某个节点(node)上引用了CSS或者 IMAGE,就会再发1个request去请求CSS或image,然后继续执行下面的转换,而不需要等待request的返回,当request返回 后,只需要把返回的内容放入到DOM树中对应的位置就OK。
下面的代码会先弹出"head js"对话框,浏览器再继续分析文档DOM结构,此时"Hello World"文本才呈现。然后再弹出"body js"对话框,"Try hard!"文本呈现。
<!DOCTYPE html> <html> <head> <title></title> <script>alert("head js")</script> </head> <body> <h1>Hello World!</h1> <script>alert("body js")</script> <h2>Try hard!</h2> </body> </html>
解决方法:
设置<script defer="defer"></script>,脚本会被延迟到整个页面都解析完毕再运行。即告诉浏览器立即下载,但延迟执行。
defer属性只适用于外部脚本,IE4-IE7还支持内联脚本,IE8,FF3.5,Safari5,Chrome会忽略内联脚本的defer属性。
HTML5定义了一个属性async与defer类似,但并不保证它们的先后执行顺序,所以确保它们互不依赖。FF3.6,Safari5,Chrome支持。
还有一种常用的方法,就是把延迟脚本放在页面底部。
最后介绍一种动态脚本方法。
function loadScript(url){
var script = document.createElement("script");
script.type = "text/javascript";
script.src = url;
document.body.appendChild(script);
}