编写高性能的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 相关文章推荐
YUI 读码日记之 YAHOO.lang.is*
Mar 22 Javascript
jquery实现点击文字可编辑并修改保存至数据库
Apr 15 Javascript
jQuery中的read和JavaScript中的onload函数的区别
Aug 27 Javascript
详解JavaScript中的every()方法
Jun 08 Javascript
浅析JS原型继承与类的继承
Apr 07 Javascript
JS实现拖拽的方法分析
Dec 20 Javascript
JS简单实现自定义右键菜单实例
May 31 Javascript
js事件委托和事件代理案例分享
Jul 25 Javascript
BootstrapTable加载按钮功能实例代码详解
Sep 22 Javascript
React-Router如何进行页面权限管理的方法
Dec 06 Javascript
React Router v4 入坑指南(小结)
Apr 08 Javascript
解决使用bootstrap的dropdown部件时报错:error:Bootstrap dropdown require Popper.js问题
Aug 30 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
Excel数据导入Mysql数据库的实现代码
2008/06/05 PHP
php array_udiff_assoc 计算两个数组的差集实例
2016/11/12 PHP
tp5(thinkPHP5框架)captcha验证码配置及验证操作示例
2019/05/28 PHP
S2SH整合JQuery+Ajax实现登录验证功能实现代码
2013/01/30 Javascript
js 验证密码强弱的小例子
2013/03/21 Javascript
javascript窗口宽高,鼠标位置,滚动高度(详细解析)
2013/11/18 Javascript
jQuery简单设置文本框回车事件的方法
2016/08/01 Javascript
JavaScript获取URL中参数querystring的方法详解
2016/10/11 Javascript
AngularJS实现与Java Web服务器交互操作示例【附demo源码下载】
2016/11/02 Javascript
微信小程序 解决请求服务器手机预览请求不到数据的方法
2017/01/04 Javascript
浅谈原生JS实现jQuery的animate()动画示例
2017/03/08 Javascript
node.js中TCP Socket多进程间的消息推送示例详解
2018/07/10 Javascript
微信小程序mpvue点击按钮获取button值的方法
2019/05/29 Javascript
Vue实现简单的留言板
2020/10/23 Javascript
python微信撤回监测代码
2019/04/29 Python
解决pycharm上的jupyter notebook端口被占用问题
2019/12/17 Python
解决springboot yml配置 logging.level 报错问题
2020/02/21 Python
Python开发之身份证验证库id_validator验证身份证号合法性及根据身份证号返回住址年龄等信息
2020/03/20 Python
django日志默认打印request请求信息的方法示例
2020/05/17 Python
python通用数据库操作工具 pydbclib的使用简介
2020/12/21 Python
通过python-pptx模块操作ppt文件的方法
2020/12/26 Python
详解Python模块化编程与装饰器
2021/01/16 Python
AVON雅芳官网:世界上最大的美容化妆品公司之一
2016/11/02 全球购物
佳能英国官方网站:Canon UK
2017/08/08 全球购物
印度尼西亚最好的小工具在线商店:Erafone.com
2019/03/26 全球购物
俄语翻译实习生的自我评价分享
2013/11/06 职场文书
八一演出活动方案
2014/02/03 职场文书
大学生创业项目方案
2014/03/08 职场文书
公司合作协议书范本
2014/04/18 职场文书
母亲节演讲稿
2014/05/27 职场文书
师德模范事迹材料
2014/06/03 职场文书
毕业实习自我鉴定范文2014
2014/09/26 职场文书
违章停车检讨书
2014/10/21 职场文书
初中家长评语大全
2014/12/26 职场文书
初中地理教学反思
2016/02/19 职场文书
Java 多线程协作作业之信号同步
2022/05/11 Java/Android