编写高性能的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 相关文章推荐
JS图片浏览组件PhotoLook的公开属性方法介绍和进阶实例代码
Nov 09 Javascript
jquery中通过父级查找进行定位示例
Jun 28 Javascript
jQuery选择器源码解读(四):tokenize方法的Expr.preFilter
Mar 31 Javascript
jQuery简单实现两级下拉菜单效果代码
Sep 15 Javascript
jQuery+HTML5美女瀑布流布局实现方法
Sep 21 Javascript
js中对函数设置默认参数值的3种方法
Oct 23 Javascript
JS及PHP代码编写八大排序算法
Jul 12 Javascript
浅谈Node.js ORM框架Sequlize之表间关系
Jul 24 Javascript
AngularJs每天学习之总体介绍
Aug 07 Javascript
javascript中一些奇葩的日期换算方法总结
Nov 14 Javascript
js实现双色球效果
Aug 02 Javascript
Openlayers绘制聚合标注
Sep 28 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
dedecms模板标签代码官方参考
2007/03/17 PHP
php5.3中连接sqlserver2000的两种方法(com与ODBC)
2012/12/29 PHP
php设计模式之观察者模式的应用详解
2013/05/21 PHP
如何在PHP中使用AES加密算法加密数据
2020/06/24 PHP
jQuery入门问答 整理的几个常见的初学者问题
2010/02/22 Javascript
JavaScript 语言的递归编程
2010/05/18 Javascript
jQuery+ajax实现顶一下,踩一下效果
2010/07/17 Javascript
JavaScript中的property和attribute介绍
2011/12/26 Javascript
jQuery窗口、文档、网页各种高度的精确理解
2014/07/02 Javascript
JS控制表单提交的方法
2015/07/09 Javascript
Angular.js中ng-if、ng-show和ng-hide的区别介绍
2017/01/20 Javascript
原生JS实现图片翻书效果
2017/02/16 Javascript
大白话讲解JavaScript的Promise
2017/04/06 Javascript
JS运动特效之任意值添加运动的方法分析
2018/01/24 Javascript
原生js实现弹窗消息动画
2020/11/20 Javascript
vue项目中企业微信使用js-sdk时config和agentConfig配置方式详解
2020/12/15 Vue.js
python的三目运算符和not in运算符使用示例
2014/03/03 Python
Python开发WebService系列教程之REST,web.py,eurasia,Django
2014/06/30 Python
Python with的用法
2014/08/22 Python
python实现两个dict合并与计算操作示例
2019/07/01 Python
Kali Linux安装ipython2 和 ipython3的方法
2019/07/11 Python
详解Django 时间与时区设置问题
2019/07/23 Python
python多线程分块读取文件
2019/08/29 Python
利用python制作拼图小游戏的全过程
2020/12/04 Python
CSS3中的content属性使用示例
2015/07/20 HTML / CSS
html5基础教程常用技巧整理
2013/08/20 HTML / CSS
使用 HTML5 Canvas 制作水波纹效果点击图片就会触发
2014/09/15 HTML / CSS
介绍JAVA 中的Collection FrameWork(及如何写自己的数据结构)
2014/10/31 面试题
创业计划书中包含的9个方面
2013/12/26 职场文书
《临死前的严监生》教学反思
2014/02/13 职场文书
金融事务专业求职信
2014/04/25 职场文书
2014光棍节单身联谊活动策划书
2014/10/10 职场文书
2014年工程工作总结
2014/11/25 职场文书
秋季运动会加油词
2015/07/18 职场文书
基于Pygame实现简单的贪吃蛇游戏
2021/12/06 Python
vue二维数组循环嵌套方式 循环数组、循环嵌套数组
2022/04/24 Vue.js