编写高性能的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 相关文章推荐
HTML代码中标签的全部属性 中文注释说明
Mar 26 Javascript
JavaScript导出Excel实例详解
Nov 25 Javascript
Svg.js实例教程及使用手册详解(一)
May 16 Javascript
AngularJS 模块化详解及实例代码
Sep 14 Javascript
ES6正则的扩展实例详解
Apr 25 Javascript
浅谈Vuejs Prop基本用法
Aug 17 Javascript
详解vue mint-ui源码解析之loadmore组件
Oct 11 Javascript
微信小程序Getuserinfo解决方案图解
Aug 24 Javascript
JS对象和字符串之间互换操作实例分析
Feb 02 Javascript
Vue3.0中的monorepo管理模式的实现
Oct 14 Javascript
解决vue 给window添加和移除resize事件遇到的坑
Jul 21 Javascript
Angular利用HTTP POST下载流文件的步骤记录
Jul 26 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中获取内网用户MAC地址(WINDOWS/linux)的实现代码
2011/08/11 PHP
php中echo()和print()、require()和include()等易混淆函数的区别
2012/02/22 PHP
php使用curl模拟登录后采集页面的例子
2013/11/04 PHP
php获取指定范围内最接近数的方法
2015/06/02 PHP
PHP+Redis 消息队列 实现高并发下注册人数统计的实例
2018/01/29 PHP
laravel框架数据库操作、查询构建器、Eloquent ORM操作实例分析
2019/12/20 PHP
20个非常有用的PHP类库 加速php开发
2010/01/15 Javascript
jQuery 无限级菜单的简单实例
2014/02/21 Javascript
JavaScript中的类数组对象介绍
2014/12/30 Javascript
javascript闭包(Closure)用法实例简析
2015/11/30 Javascript
jQuery实现获取绑定自定义事件元素的方法
2015/12/02 Javascript
jQuery移动web开发中的页面初始化与加载事件
2015/12/03 Javascript
JS获取文件大小方法小结
2015/12/08 Javascript
Vue2实现组件props双向绑定
2016/12/02 Javascript
微信开发之调起摄像头、本地展示图片、上传下载图片实例
2016/12/08 Javascript
knockoutjs模板实现树形结构列表
2017/07/31 Javascript
react-redux中connect的装饰器用法@connect详解
2018/01/13 Javascript
jquery UI实现autocomplete在获取焦点时得到显示列表功能示例
2019/06/04 jQuery
SSM+layUI 根据登录信息显示不同的页面方法
2019/09/20 Javascript
vue中使用element ui的弹窗与echarts之间的问题详解
2019/10/25 Javascript
python实现linux下使用xcopy的方法
2015/06/28 Python
Python时间序列处理之ARIMA模型的使用讲解
2019/04/02 Python
python 利用jinja2模板生成html代码实例
2019/10/10 Python
NBA欧洲商店(西班牙):NBA Europe Store ES
2019/04/16 全球购物
STRATHBERRY苏贝瑞包包官网:西班牙高级工匠手工打造
2020/11/10 全球购物
应届毕业生自我鉴定范文
2013/12/27 职场文书
竞聘副主任科员演讲稿
2014/01/11 职场文书
文明学生标兵事迹
2014/01/21 职场文书
我的动漫时代的创业计划书范文
2014/01/27 职场文书
优秀学生获奖感言
2014/02/15 职场文书
读书伴我成长演讲稿
2014/05/07 职场文书
龙门石窟导游词
2015/02/02 职场文书
答谢酒会主持词
2015/07/02 职场文书
Python基于Opencv识别两张相似图片
2021/04/25 Python
python3实现无权最短路径的方法
2021/05/12 Python
TV动画「神渣☆爱豆」公开第一弹主视觉图
2022/03/21 日漫