编写高性能的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 相关文章推荐
getElementsByTagName vs selectNodes效率 及兼容的selectNodes实现
Feb 26 Javascript
前端开发必须知道的JS之原型和继承
Jul 06 Javascript
jquery 查找select ,并触发事件的实现代码
Mar 30 Javascript
页面加载完后自动执行一个方法的js代码
Sep 06 Javascript
跟我学习javascript的全局变量
Nov 16 Javascript
Jquery实现select multiple左右添加和删除功能的简单实例
May 26 Javascript
jQuery插件HighCharts绘制2D圆环图效果示例【附demo源码下载】
Mar 09 Javascript
JavaScript程序设计高级算法之动态规划实例分析
Nov 24 Javascript
jQuery中实现text()的方法
Apr 04 jQuery
3分钟读懂移动端rem使用方法(推荐)
May 06 Javascript
Vue通过WebSocket建立长连接的实现代码
Nov 05 Javascript
谈谈JavaScript中的垃圾回收机制
Sep 17 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与javascript对多项选择的处理
2006/10/09 PHP
关于js和php对url编码的处理方法
2014/03/04 PHP
php调用c接口无错版介绍
2014/03/11 PHP
php实现数据库的增删改查
2017/02/26 PHP
PHP safe_mode开启对于PHP系统函数有什么影响
2020/11/10 PHP
静态页面下用javascript操作ACCESS数据库(读增改删)的代码
2007/05/14 Javascript
推荐17个优美新鲜的jQuery的工具提示插件
2012/09/14 Javascript
js/html光标定位的实现代码
2013/09/23 Javascript
JavaScript charCodeAt方法入门实例(用于取得指定位置字符的Unicode编码)
2014/10/17 Javascript
JQUERY的AJAX请求缓存里的数据问题处理
2016/02/23 Javascript
理解Javascript图片预加载
2016/02/23 Javascript
基于JS实现的随机数字抽签实例
2016/12/08 Javascript
详谈js中数组(array)和对象(object)的区别
2017/02/27 Javascript
vue 打包后的文件部署到express服务器上的方法
2017/08/09 Javascript
详解react-router4 异步加载路由两种方法
2017/09/12 Javascript
vue.js做一个简单的编辑菜谱功能
2018/05/08 Javascript
纯javascript实现选择框的全选与反选功能
2019/04/08 Javascript
小程序:授权、登录、session_key、unionId的详解
2019/05/15 Javascript
pymssql ntext字段调用问题解决方法
2008/12/17 Python
python里将list中元素依次向前移动一位
2014/09/12 Python
详解Django的model查询操作与查询性能优化
2018/10/16 Python
python中PS 图像调整算法原理之亮度调整
2019/06/28 Python
python Opencv计算图像相似度过程解析
2019/12/03 Python
Python对象的属性访问过程详解
2020/03/05 Python
使用纯 CSS 创作一个脉动 loader效果的源码
2018/09/28 HTML / CSS
Omio意大利:全欧洲低价大巴、火车和航班搜索和比价
2017/12/02 全球购物
中国制造网:Made-in-China.com
2019/10/25 全球购物
Under Armour安德玛意大利官网:美国高端运动科技品牌
2020/01/16 全球购物
大学毕业生自荐书怎么写?
2014/01/06 职场文书
自我鉴定书面格式
2014/01/13 职场文书
大一新生学期自我评价
2014/04/09 职场文书
优秀驾驶员先进事迹材料
2014/05/04 职场文书
2014迎国庆演讲稿
2014/09/19 职场文书
医院保洁员管理制度
2015/08/05 职场文书
教你用Python爬取英雄联盟皮肤原画
2021/06/13 Python
go select编译期的优化处理逻辑使用场景分析
2021/06/28 Golang