编写高性能的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_08_函数对象
Oct 15 Javascript
JS实现一个按钮的方法
Feb 05 Javascript
JavaScript中Number.MAX_VALUE属性的使用方法
Jun 04 Javascript
javascript自定义滚动条实现代码
Apr 20 Javascript
JS自定义混合Mixin函数示例
Nov 26 Javascript
arcgis for js栅格图层叠加(Raster Layer)问题
Nov 22 Javascript
详解Vue快速零配置的打包工具——parcel
Jan 16 Javascript
React中使用UEditor百度富文本的方法
Aug 22 Javascript
vue-router 中 meta的用法详解
Nov 01 Javascript
Vue是怎么渲染template内的标签内容的
Jun 05 Javascript
vue实现移动端触屏拖拽功能
Aug 21 Javascript
vue 如何使用递归组件
Oct 23 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
几种显示数据的方法的比较
2006/10/09 PHP
PHP用户注册邮件激活账户的实现代码
2017/05/31 PHP
PHP分享图片的生成方法
2018/04/25 PHP
javascript上下方向键控制表格行选中并高亮显示的方法
2015/02/13 Javascript
JavaScript中的立即执行函数表达式介绍
2015/03/15 Javascript
JavaScript中的setUTCDate()方法使用详解
2015/06/11 Javascript
jquery validate和jquery form 插件组合实现验证表单后AJAX提交
2015/08/26 Javascript
js HTML5多图片上传及预览实例解析(不含前端的文件分割)
2016/08/26 Javascript
JavaScript 数组的深度复制解析
2016/11/02 Javascript
ES6下React组件的写法示例代码
2017/05/04 Javascript
nodejs body-parser 解析post数据实例
2017/07/26 NodeJs
Angular.js初始化之ng-app的自动绑定与手动绑定详解
2017/07/31 Javascript
es6学习之解构时应该注意的点
2017/08/29 Javascript
JavaScript正则表达式的贪婪匹配和非贪婪匹配
2017/09/05 Javascript
jQuery 实现倒计时天,时,分,秒功能
2018/07/31 jQuery
ES6中字符串的使用方法扩展
2019/06/04 Javascript
javascript 构建模块化开发过程解析
2019/09/11 Javascript
Django中传递参数到URLconf的视图函数中的方法
2015/07/18 Python
python3中int(整型)的使用教程
2017/03/23 Python
Python批量删除只保留最近几天table的代码实例
2019/04/01 Python
详解python 爬取12306验证码
2019/05/10 Python
Python+AutoIt实现界面工具开发过程详解
2019/08/07 Python
Python随机函数库random的使用方法详解
2019/08/21 Python
Python venv虚拟环境配置过程解析
2020/07/08 Python
CSS3+DIV实现漂亮的动画彩色标签
2016/06/16 HTML / CSS
用CSS3实现无限循环的无缝滚动的实例代码
2017/07/04 HTML / CSS
KIKO MILANO英国官网:意大利知名化妆品和护肤品品牌
2017/09/25 全球购物
英国综合网上购物商城:The Hut
2018/07/03 全球购物
俄罗斯药房连锁店:ASNA
2020/06/20 全球购物
法律专业个人实习自我鉴定
2013/09/23 职场文书
高中学校对照检查材料
2014/08/31 职场文书
2014年机关党建工作总结
2014/11/11 职场文书
2015年党员公开承诺书范文
2015/01/22 职场文书
工作简报怎么写
2015/07/21 职场文书
财务会计个人原因辞职信
2019/06/21 职场文书
创业计划书之便利店
2019/09/05 职场文书