如何确保JavaScript的执行顺序 之实战篇


Posted in Javascript onMarch 03, 2011

1. 引言
我曾在文章《如何在多个页面使用同一个HTML片段 - 续》的最后提到JavaScript顺序执行的特性。虽然现代浏览器可以并行的下载JavaScript(部分浏览器),但考虑到JavaScript的依赖关系,他们的执行依然是按照引入顺序进行的。
为了更好的测试这个过程,我写了一个简单的HTTP处理程序页面 service.ashx,它可以接受两个参数:
1. file,需要返回文件的服务器端路径。
2. delay,延迟一定时间后再返回本次HTTP请求(毫秒)。
一个典型的页面比如:./service.ashx?file=js/jquery-ui.js&delay=2000,表示延迟2秒钟后再返回服务器端的js/jquery-ui.js文件。
service.ashx 的关键代码如下:

public void ProcessRequest(HttpContext context) 
{ 
int delay = 0; 
if (!String.IsNullOrEmpty(context.Request["delay"])) 
{ 
delay = Convert.ToInt32(context.Request["delay"]); 
} 
if (delay > 0) 
{ 
System.Threading.Thread.Sleep(1000); 
} 
string filePath = context.Request["file"].ToString(); 
string fileContent = String.Empty; 
using (StreamReader sr = new StreamReader(context.Server.MapPath(filePath))) 
{ 
fileContent = sr.ReadToEnd(); 
} 
if (filePath.EndsWith(".js")) 
{ 
context.Response.ContentType = "application/x-javascript"; 
} 
else 
{ 
context.Response.ContentType = "text/plain"; 
} 
context.Response.Write(fileContent); 
}

2. 通过script标签直接引入JavaScript(test1.htm)
首先我们分析下在<head>标签中顺序引入JavaScript的情况。test1.htm的页面源代码如下:
<html> 
<head> 
<title></title> 
<script src="./js/jquery-1.4.4.js" 
type="text/javascript"></script> 
<script src="./service.ashx?file=js/jquery-ui.js&delay=2000" 
type="text/javascript"></script> 
<script> 
alert(typeof (jQuery.ui)); 
</script> 
</head> 
<body> 
</body> 
</html>

我们分别在各种浏览器中测试这个例子:
test1.htm
通过script标签直接引入JavaScript
Firefox 3.6
IE 8
Chrome 10
Safari 4
Opera 11

 

可以看出各个主流浏览器的行为一致。虽然jQueryUI在服务器延迟了2秒钟再返回,但是后引入的内联JavaScript还是等待了2秒,等前面引入的JavaScript执行完毕才执行。这也是著名的JavaScript顺序执行的特性。
3. 通过JavaScript添加script标签(test3.htm)
我们首先定义一个addScript函数,用来引入外部或者内联JavaScript。test3.htm的页面源代码如下:

<html> 
<head> 
<title></title> 
<script src="./js/jquery-1.4.4.js" type="text/javascript"></script> 
<script> 
function addScript(url, inline) { 
var head = document.getElementsByTagName("head")[0]; 
var script = document.createElement('script'); 
script.type = 'text/javascript'; 
if (inline) { 
script.text = url; 
} else { 
script.src = url; 
} 
head.appendChild(script); 
} 
$(function () { 
addScript('./service.ashx?file=js/jquery-ui.js&delay=2000'); 
addScript('alert(typeof(jQuery.ui));', true); 
}); 
</script> 
</head> 
<body> 
<div id="container"> 
</div> 
</body> 
</html>

我们分别在各种浏览器中测试这个例子:
test3.htm
通过JavaScript添加<script>标签
Firefox 3.6
IE 8
Chrome 10
Safari 4
Opera 11

可见,通过JavaScriptDOM加载完毕后再引入外部或者内联JavaScript时,FirefoxOpera的行为一致,能够确保JavaScript的执行顺序和引入顺序一致。但是IE8, Chrome, Safari 却不能保证这个执行顺序。

虽然各种浏览器在确保执行顺序方面不尽相同,不过这时的最大好处是多个JavaScript文件能够并行下载,这在所有浏览器中行为一致。当然这不是这篇文章的主题,可以Google更多细节

如何解决各个浏览器的不一致性,下面提供了两个解决方案:
4. 方案一,如何在动态添加script标签时确保执行顺序
有时页面逻辑要求我们必须通过上面的方式动态执行JavaScript,那么如何确保所有浏览器下的执行顺序(目前只有Firefox和Opera确保执行顺序)。
其实解决方案很简单,我们为函数执行添加一个complete的回调函数就行了。下面的test4.htm给出了具体的解决方案:

<html> 
<head> 
<title></title> 
<script src="./js/jquery-1.4.4.js" type="text/javascript"></script> 
<script> 
function addScript(url, inline, callback) { 
var head = document.getElementsByTagName("head")[0]; 
var script = document.createElement('script'); 
script.type = 'text/javascript'; 
if (inline) { 
script.text = url; 
} else { 
script.src = url; 
script.onload = script.onreadystatechange = function () { 
if (!script.readyState || script.readyState === 'loaded' || script.readyState === 'complete') { 
if (callback) { 
callback(); 
} 
script.onload = script.onreadystatechange = null; 
}; 
}; 
} 
head.appendChild(script); 
if (inline && callback) { 
callback(); 
} 
} 
$(function () { 
addScript('./service.ashx?file=js/jquery-ui.js&delay=2000', false, function () { 
addScript('alert(typeof(jQuery.ui));', true); 
}); 
}); 
</script> 
</head> 
<body> 
<div id="container"> 
</div> 
</body> 
</html>

此时所有浏览器中的行为一致:
test4.htm
通过回调函数解决动态添加JavaScript的顺序问题
Firefox 3.6
IE 8
Chrome 10
Safari 4
Opera 11

5. 方案二,使用jQuery的html函数动态添加JavaScript
jQuery的html函数用来更新一个DOM片段,我们可以很方便的通过这个函数来动态加载JavaScript,请看示例test2.htm:
<html> 
<head> 
<title></title> 
<script src="js/jquery-1.4.4.js" type="text/javascript"></script> 
<script> 
$(function(){ 
$('#container').html('<script src="./service.ashx?file=js/jquery-ui.js&delay=2000" type="text\/javascript"><\/script>' + '<script>alert(typeof(jQuery.ui));<\/script>'); 
}); 
</script> 
</head> 
<body> 
<div id="container"> 
</div> 
</body> 
</html>

此时,各个浏览器中的行为一致:
test2.htm
通过jQuery的html函数解决动态添加JavaScript的顺序问题
Firefox 3.6
IE 8
Chrome 10
Safari 4
Opera 11

6. 后记
为什么jQuery的html函数能够确保动态加载JavaScript的执行顺序呢?
我们知道通过简单的 .innerHTML 更新DOM节点,是不会让其中的JavaScript的执行,我们可以简单的把这个例子的源代码改成:
$('#container')[0].innerHTML = '<script src="./service.ashx?file=js/jquery-ui.js&delay=2000" type="text\/javascript"><\/script>' + '<script>alert(typeof(jQuery.ui));<\/script>';
这种情况下jQueryUI根本不会加载。
那么jQuery是如果做到的呢?下篇文章我们会追根溯源,详细分析jQuery源代码,请继续浏览: 如何确保JavaScript的执行顺序 ? 之jQuery.html深度分析

Javascript 相关文章推荐
JQuery 学习笔记 选择器之四
Jul 23 Javascript
js 获取子节点函数 (兼容FF与IE)
Apr 18 Javascript
jquery each()源代码
Feb 14 Javascript
JavaScript的Backbone.js框架的一些使用建议整理
Feb 14 Javascript
Jquery技巧(必须掌握)
Mar 16 Javascript
JavaScript中的普通函数和箭头函数的区别和用法详解
Mar 21 Javascript
webpack配置sass模块的加载的方法
Jul 30 Javascript
ReactJs实现树形结构的数据显示的组件的示例
Aug 18 Javascript
详解Js中的模块化是如何实现的
Oct 18 Javascript
react router4+redux实现路由权限控制的方法
May 03 Javascript
自定义Vue中的v-module双向绑定的实现
Apr 17 Javascript
浅谈layui 绑定form submit提交表单的注意事项
Oct 25 Javascript
如何确保JavaScript的执行顺序 之jQuery.html并非万能钥匙
Mar 03 #Javascript
如何确保JavaScript的执行顺序 之jQuery.html深度分析
Mar 03 #Javascript
jQuery 操作option的实现代码
Mar 03 #Javascript
基于Jquery的$.cookie()实现跨越页面tabs导航实现代码
Mar 03 #Javascript
jquery中实现简单的tabs插件功能的代码
Mar 02 #Javascript
基于jQuery的简单的列表导航菜单
Mar 02 #Javascript
jquery异步调用页面后台方法&amp;#8207;(asp.net)
Mar 01 #Javascript
You might like
DW中链接mysql数据库时,建立字符集中文出现乱码的解决方法
2010/03/27 PHP
mysql 查询指定日期时间内sql语句实现原理与代码
2012/12/16 PHP
PHP函数实现分页含文本分页和数字分页
2014/10/23 PHP
PHP中preg_match正则匹配中的/u、/i、/s含义
2015/04/17 PHP
php实现在服务器端调整图片大小的方法
2015/06/16 PHP
PHP抓取网页、解析HTML常用的方法总结
2015/07/01 PHP
PHP实现动态web服务器方法
2015/07/29 PHP
PHP htmlspecialchars()函数用法与实例讲解
2019/03/08 PHP
FLASH 广告之外的链接
2008/12/16 Javascript
Mozilla 表达式 __noSuchMethod__
2009/04/05 Javascript
json数据处理技巧(字段带空格、增加字段、排序等等)
2013/06/14 Javascript
Javascript限制网页只能在微信内置浏览器中访问
2014/11/09 Javascript
JavaScript的兼容性与调试技巧
2016/11/22 Javascript
Ajax跨域实现代码(后台jsp)
2017/01/21 Javascript
javascript实现秒表计时器的制作方法
2017/02/16 Javascript
AngularJS之页面跳转Route实例代码
2017/03/10 Javascript
layui框架中layer父子页面交互的方法分析
2017/11/15 Javascript
解决axios post 后端无法接收数据的问题
2019/10/29 Javascript
Vue + element 实现多选框组并保存已选id集合的示例代码
2020/06/03 Javascript
最全vue的vue-amap使用高德地图插件画多边形范围的示例代码
2020/07/17 Javascript
JavaScript实现缓动动画
2020/11/25 Javascript
[05:29]2014DOTA2国际邀请赛 赛后专访:LGDNewbee顺利过关
2014/07/13 DOTA
Python创建数字列表的示例
2019/11/28 Python
Python Django中间件使用原理及流程分析
2020/06/13 Python
CSS3+JavaScript实现炫酷呼吸效果的示例代码
2020/06/15 HTML / CSS
英国汽车和货车租赁网站:Hertz英国
2016/09/02 全球购物
怀旧收藏品和经典纪念品:Betty’s Attic
2018/08/29 全球购物
分布式数据库需要考虑哪些问题
2013/12/08 面试题
服装设计专业自荐书范文
2013/12/30 职场文书
计算机应用专业毕业生求职信
2014/06/03 职场文书
中药学专业毕业生推荐信
2014/07/10 职场文书
教师辞职信范文
2015/02/28 职场文书
2015年医务人员医德医风自我评价
2015/03/03 职场文书
2015年检验科工作总结
2015/04/27 职场文书
2016年先进班集体事迹材料
2016/02/26 职场文书
读《推着妈妈去旅行》有感1500字
2019/10/15 职场文书