编写高性能的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所必须要知道的一些
Mar 07 Javascript
js获取时间(本周、本季度、本月..)
Nov 22 Javascript
JQEasy-ui在IE9以下版本中二次加载的问题分析及处理方法
Jun 23 Javascript
AngularJS身份验证的方法
Feb 17 Javascript
Vue表单实例代码
Sep 05 Javascript
js+html5实现复制文字按钮
Jul 15 Javascript
微信小程序实现留言板
Oct 31 Javascript
微信小程序实现登录遮罩效果
Nov 01 Javascript
Vue在 Nuxt.js 中重定向 404 页面的方法
Apr 23 Javascript
泛谈JS逻辑判断选择器 || &amp;&amp;
May 24 Javascript
vue 在methods中调用mounted的实现操作
Aug 07 Javascript
Three.js实现雪糕地球的使用示例详解
Jul 07 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+redis实现添加处理投票的方法
2015/11/14 PHP
Thinkphp整合微信支付功能
2016/12/14 PHP
yii2.0整合阿里云oss上传单个文件的示例
2017/09/19 PHP
PHP实用小技巧之调用录像的方法
2019/12/05 PHP
TP5(thinkPHP5)框架使用ajax实现与后台数据交互的方法小结
2020/02/10 PHP
flexigrid 类似ext grid的JS表格代码
2010/07/17 Javascript
在JavaScript中获取请求的URL参数[正则]
2010/12/25 Javascript
按给定几率进行随机抽取的js代码
2010/12/28 Javascript
初学js 新节点的创建 删除 的步骤
2011/07/04 Javascript
JS模拟面向对象全解(二、类型与赋值)
2011/07/13 Javascript
基于jquery fly插件实现加入购物车抛物线动画效果
2016/04/05 Javascript
AngularJS基础 ng-model 指令详解及示例代码
2016/08/02 Javascript
BootStrap modal模态弹窗使用小结
2016/10/26 Javascript
Bootstrap实现的标签页内容切换显示效果示例
2017/05/25 Javascript
js 概率计算(简单版)
2017/09/12 Javascript
Electron-vue开发的客户端支付收款工具的实现
2019/05/24 Javascript
layui使用label标签的方法
2019/09/14 Javascript
微信小程序实现加入购物车滑动轨迹
2020/11/18 Javascript
详解Vue.js 可拖放文本框组件的使用
2021/03/03 Vue.js
Python中解析JSON并同时进行自定义编码处理实例
2015/02/08 Python
在Django中使用Sitemap的方法讲解
2015/07/22 Python
python 表达式和语句及for、while循环练习实例
2017/07/07 Python
详解Django中CBV(Class Base Views)模型源码分析
2019/02/25 Python
pandas DataFrame 交集并集补集的实现
2019/06/24 Python
Nginx+Uwsgi+Django 项目部署到服务器的思路详解
2020/05/08 Python
使用python创建生成动态链接库dll的方法
2020/05/09 Python
Python如何在windows环境安装pip及rarfile
2020/06/15 Python
美国著名首饰网站:BaubleBar
2016/08/29 全球购物
美国知名奢侈美容品牌零售商:Cos Bar
2017/04/21 全球购物
sealed修饰符是干什么的
2012/10/23 面试题
通信工程专业女生个人求职信
2013/09/21 职场文书
超级搞笑检讨书
2014/01/15 职场文书
领导批评与自我批评范文
2014/10/16 职场文书
活动宣传稿范文
2015/07/23 职场文书
新手必备Python开发环境搭建教程
2021/05/28 Python
html解决浏览器记住密码输入框的问题
2023/05/07 HTML / CSS