编写高性能的JavaScript 脚本的加载与执行


Posted in Javascript onApril 19, 2010

脚本可以放在html页面的head里面,也可以放在body里面。
把脚本放在body中,当浏览器遇见<script>标签时, 浏览器不知道脚本会插入文本还是html标签,因此浏览器会停止分析html页面而去执行脚本。当使用src的方式添加脚本时,浏览器也会做同样的动作。在脚本处理的时候,页面呈现和用户交互将被完全阻止。脚本下载和执行阻塞了其他资源的下载,比如呈现页面使用的图片。(虽然很多浏览器实现了脚本并行下载的技术,但是这个问题依然没有解决)
脚本的位置
鉴于上面的理由,脚本应该始终放在页面的底部,即</body>前面。
一个简单的示例:

<html> 
<head> 
<title>Script Example</title> 
<link rel="stylesheet" type="text/css" href="styles.css"> 
</head> 
<body> 
<p>Hello world!</p> 
<script type="text/javascript" src="file1.js"></script> 
<script type="text/javascript" src="file2.js"></script> 
<script type="text/javascript" src="file3.js"></script> 
</body> 
</html>

合并脚本
因为脚本下载阻塞了页面呈现,因而应该减少页面<script>标签的使用,不管脚本是内联的还是外部的。在处理外部脚本的时候情况比较特殊,浏览器下载一个100kb的脚本的时间将远远小于4个25kb的脚本,因为建立一个请求要消耗大量的时间。所以页面应该尽量的减少外部脚本的引用。
非阻塞的脚本
秘诀在于当页面loading完成之后再来加载脚本,也就是在window对象的onload事件触发之前 。下面是实现的几种方式:
1.使用defer
<html> 
<head> 
<title>Script Defer Example</title> 
</head> 
<body> 
<script defer> 
alert("defer"); 
</script> 
<script> 
alert("script"); 
</script> 
<script> 
window.onload = function(){ 
alert("load"); 
}; 
</script> 
</body> 
</html>

页面弹出框出现的顺序: script/defer/load,这个技术的缺点是IE4+和FF3.5+才支持。
非阻塞的脚本(续)
2. 动态脚本元素
要知道<script>和普通的html标签并没有本质的区别,所以可以利用标准的DOM方法动态的添加脚本文件引用。方法如下:
var script = document.createElement("script"); 
script.type = "text/javascript"; 
script.src = "file1.js"; 
document.getElementsByTagName("head")[0].appendChild(script);

当这个标签一旦加入到html中,脚本文件就开始下载。这种方法的一个特点就是,文件下载和执行并不阻塞html页面其它部分的处理。通常将这样的脚本放在<head>中较之<body>更加安全,尤其是文件包含的代码需要在页面的load事件中执行。如果body的内容还没有被完全的加载,IE还会弹出“禁止操作”的错误。
当脚本文件下载完成之后,脚本立即执行(FF、Opera会等待前一个以同样方式添加的脚本执行)。当脚本自执行时,这没什么问题。但是如果脚本包含页面中其它脚本使用的interfaces,你需要确认脚本已经加载完成并且可用。幸好,当获得script标签的src的值之后,Firefox, Opera, Chrome, and Safari 3+ 会触发一个load事件。
var script = document.createElement("script") 
script.type = "text/javascript"; 
//Firefox, Opera, Chrome, Safari 3+ 
script.onload = function(){ 
alert("Script loaded!"); 
}; 
script.src = "file1.js"; 
document.getElementsByTagName("head")[0].appendChild(script);

IE则提供了另外一种解决方案--readystatechange事件。根据下载
脚本文件所处的状态,readyState 的值有以下几种:
"uninitialized"
默认状态
"loading"
开始下载
"loaded"
下载完成
"interactive"
下载完成,但是并非全部可用
"complete"
所有数据可用
IE的实现方式:
var script = document.createElement("script") 
script.type = "text/javascript"; 
script.onreadystatechange = function(){ 
if (script.readyState == "loaded" || script.readyState == "complete"){ 
script.onreadystatechange = null; 
alert("Script loaded."); 
} 
}; 
script.src = "file1.js"; 
document.getElementsByTagName("head")[0].appendChild(script);

下面是综合以后的通用方法:
function loadScript(url, callback){ 
var script = document.createElement("script") 
script.type = "text/javascript"; 
if (script.readyState){ //IE 
script.onreadystatechange = function(){ 
if (script.readyState == "loaded" || script.readyState == "complete"){ 
script.onreadystatechange = null; 
callback(); 
} 
}; 
} else { //Others 
script.onload = function(){ 
callback(); 
}; 
} 
script.src = url; 
document.getElementsByTagName("head")[0].appendChild(script); 
} 
The loadScript() function is used as follows: 
loadScript("file1.js", function(){ 
alert("File is loaded!"); 
});

现在你可以按这种动态方式加载脚本了,但是你仍然需要考虑这些文件的下载顺序。主流浏览器中只有FF和Opera保证脚本的执行顺序和你指定的下载顺序一致,其他浏览器将按照脚本文件从服务器返回的顺序来执行。虽然如此,我们仍然有替代的解决方案:
loadScript("file1.js", function(){ 
loadScript("file2.js", function(){ 
loadScript("file3.js", function(){ 
alert("All files are loaded!"); 
}); 
}); 
});

这样我们就能保证脚本文件的下载顺序严格的按照file1-file2-file3的方式进行。
注明:以上内容来自:<High Performance JavaScript>by Nicholas C. Zakas
Javascript 相关文章推荐
一个JavaScript继承的实现
Oct 24 Javascript
jquery里的正则表达式说明
Aug 03 Javascript
js获取select选中的option的text示例代码
Dec 19 Javascript
解决同一页面中两个iframe互相调用jquery,js函数的方法
Dec 12 Javascript
js仿搜狐视频记录片列表展示效果
May 30 Javascript
微信小程序 template模板详解及实例
Feb 21 Javascript
详解angularJS动态生成的页面中ng-click无效解决办法
Jun 19 Javascript
使用vue-cli打包过程中的步骤以及问题的解决
May 08 Javascript
实例解析Vue.js下载方式及基本概念
May 11 Javascript
Bootstrap 时间日历插件bootstrap-datetimepicker配置与应用小结
May 28 Javascript
通过js给网页加上水印背景实例
Jun 17 Javascript
JavaScript创建表格的方法
Apr 13 Javascript
jquery 关键字“拖曳搜索”之“拖曳”以及 图片“提示自适应放大”效果 的实现
Apr 18 #Javascript
jquery 新手学习常见问题解决方法
Apr 18 #Javascript
javascript 设计模式之单体模式 面向对象学习基础
Apr 18 #Javascript
js 获取子节点函数 (兼容FF与IE)
Apr 18 #Javascript
几个比较实用的JavaScript 测试及效验工具
Apr 18 #Javascript
javascript JSON操作入门实例
Apr 16 #Javascript
javascript对象之内置对象Math使用方法
Apr 16 #Javascript
You might like
PHP判断是否有Get参数的方法
2014/05/05 PHP
Ajax和PHP正则表达式验证表单及验证码
2016/09/24 PHP
PHP中大括号'{}'用法实例总结
2017/02/08 PHP
JQuery 风格的HTML文本转义
2009/07/01 Javascript
js封装的textarea操作方法集合(兼容很好)
2010/11/16 Javascript
JavaScript window.document的属性、方法和事件小结
2012/10/24 Javascript
JavaScript prototype属性深入介绍
2012/11/27 Javascript
ajax上传时参数提交不更新等相关问题
2012/12/11 Javascript
js 自定义个性下拉选择框示例
2013/08/20 Javascript
parentElement,srcElement的使用小结
2014/01/13 Javascript
Egret引擎开发指南之创建项目
2014/09/03 Javascript
jQuery选择器源码解读(八):addCombinator函数
2015/03/31 Javascript
javascript显示中文日期的方法
2015/06/18 Javascript
jQuery设置图片等比例缩小的方法
2017/04/29 jQuery
详解Vue 2.0封装axios笔记
2017/06/22 Javascript
全面介绍vue 全家桶和项目实例
2017/12/27 Javascript
基于vue的验证码组件的示例代码
2019/01/22 Javascript
extract-text-webpack-plugin用法详解
2019/02/14 Javascript
vue3实现v-model原理详解
2019/10/09 Javascript
[35:27]完美世界DOTA2联赛循环赛 GXR vs FTD BO2第二场 10.29
2020/10/29 DOTA
《Python学习手册》学习总结
2018/01/17 Python
python同时遍历数组的索引和值的实例
2018/11/15 Python
利用 PyCharm 实现本地代码和远端的实时同步功能
2020/03/23 Python
CSS3实现简易版的刮刮乐效果
2016/09/27 HTML / CSS
你应该知道的30个css选择器
2014/03/19 HTML / CSS
IE浏览器单独写CSS样式的几种方法
2014/10/14 HTML / CSS
美国存储和组织商店:The Container Store
2017/08/16 全球购物
linux面试题参考答案(5)
2016/11/05 面试题
MYSQL相比于其他数据库有哪些特点
2013/07/19 面试题
2014年新生军训方案
2014/05/01 职场文书
一年级班主任工作总结2014
2014/11/08 职场文书
2015财务年度工作总结范文
2015/05/04 职场文书
建党伟业的观后感
2015/06/01 职场文书
工作证明书
2015/06/15 职场文书
史上最全书信经典范文大全(建议收藏)
2019/07/10 职场文书
Spring this调用当前类方法无法拦截的示例代码
2022/03/20 Java/Android