编写高性能的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不同页面传值的改进版
Sep 30 Javascript
12种不宜使用的Javascript语法整理
Nov 04 Javascript
php中给js数组赋值方法
Mar 10 Javascript
jQuery插件开发的五种形态小结
Mar 04 Javascript
vue2.0多条件搜索组件使用详解
Mar 26 Javascript
解决vue组件中使用v-for出现告警问题及v for指令介绍
Nov 11 Javascript
JS实现字符串中去除指定子字符串方法分析
May 17 Javascript
vue-mugen-scroll组件实现pc端滚动刷新
Aug 16 Javascript
javascript设计模式 ? 适配器模式原理与应用实例分析
Apr 13 Javascript
javascript 代码是如何被压缩的示例代码
May 06 Javascript
element el-table表格的二次封装实现(附表格高度自适应)
Jan 19 Javascript
JavaScript实现简单拖拽效果
Sep 15 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中创建和验证哈希的简单方法实探
2015/07/06 PHP
laravel 事件/监听器实例代码
2019/04/12 PHP
YII2框架中actions的作用与使用方法示例
2020/03/13 PHP
PHP sdk实现在线打包代码示例
2020/12/09 PHP
Prototype Function对象 学习
2009/07/12 Javascript
jquery 双色表格实现代码
2009/12/08 Javascript
父节点获取子节点的字符串示例代码
2014/02/26 Javascript
JavaScript——DOM操作——Window.document对象详解
2016/07/14 Javascript
基于jQuery的AJAX和JSON实现纯html数据模板
2016/08/09 Javascript
jQuery插件HighCharts绘制2D带Label的折线图效果示例【附demo源码下载】
2017/03/08 Javascript
简单实现js轮播图效果
2017/07/14 Javascript
js实现音乐播放控制条
2017/09/09 Javascript
js定时器实现倒计时效果
2017/11/05 Javascript
bootstrap tooltips在 angularJS中的使用方法
2019/04/10 Javascript
简单了解three.js 着色器材质
2020/08/03 Javascript
Python实现自动发送邮件功能
2021/03/02 Python
Python iter()函数用法实例分析
2018/03/17 Python
python实现对指定输入的字符串逆序输出的6种方法
2018/04/26 Python
使用Python监控文件内容变化代码实例
2018/06/04 Python
Python使用jsonpath-rw模块处理Json对象操作示例
2018/07/31 Python
python绘图模块matplotlib示例详解
2019/07/26 Python
python写程序统计词频的方法
2019/07/29 Python
python2爬取百度贴吧指定关键字和图片代码实例
2019/08/14 Python
解决Pycharm 包已经下载,但是运行代码提示找不到模块的问题
2019/08/31 Python
使用django和vue进行数据交互的方法步骤
2019/11/11 Python
PyQt5+python3+pycharm开发环境配置教程
2020/03/24 Python
matplotlib设置颜色、标记、线条,让你的图像更加丰富(推荐)
2020/09/25 Python
介绍一下UNIX启动过程
2013/11/14 面试题
学习十八大精神心得体会
2013/12/31 职场文书
高三地理教学反思
2014/01/11 职场文书
大学校园活动策划书
2014/02/04 职场文书
大学专科求职信
2014/07/02 职场文书
个人欠款协议书范本2014
2014/11/02 职场文书
我的中国梦主题教育活动总结
2015/05/07 职场文书
Mongo服务重启异常问题的处理方法
2021/07/01 MongoDB
Python实现视频中添加音频工具详解
2021/12/06 Python