如何确保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 相关文章推荐
javascript attachEvent和addEventListener使用方法
Mar 19 Javascript
firefox下对ajax的onreadystatechange的支持情况分析
Dec 14 Javascript
javascript 模式设计之工厂模式学习心得
Apr 27 Javascript
jquery触发a标签跳转事件示例代码
Jul 21 Javascript
ajax与302响应代码测试
Oct 23 Javascript
Ionic快速安装教程
Jun 03 Javascript
Bootstrap分页插件之Bootstrap Paginator实例详解
Oct 15 Javascript
浅谈bootstrap使用中的一些问题以及解决过程
Oct 18 Javascript
angularjs实现的购物金额计算工具示例
May 08 Javascript
详解JavaScript中的强制类型转换
Apr 15 Javascript
原生JS实现弹幕效果的简单操作指南
Nov 10 Javascript
JavaScript的function函数详细介绍
Nov 20 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
如何将数据从文本导入到mysql
2006/10/09 PHP
php中判断数组相等的方法以及数组运算符介绍
2015/03/30 PHP
PHP文件上传问题汇总(文件大小检测、大文件上传处理)
2015/12/24 PHP
ThinkPHP+EasyUI之ComboTree中的会计科目树形菜单实现方法
2017/06/09 PHP
Laravel实现ApiToken认证请求
2019/10/14 PHP
PHP pthreads v3在centos7平台下的安装与配置操作方法
2020/02/21 PHP
tp5.1 框架数据库常见操作详解【添加、删除、更新、查询】
2020/05/26 PHP
PhpStorm2020 + phpstudyV8 +XDebug的教程详解
2020/09/17 PHP
jquery eval解析JSON中的注意点介绍
2013/08/23 Javascript
在每个匹配元素的外部插入新元素的方法
2013/12/20 Javascript
Javascript的严格模式strict mode详细介绍
2014/06/06 Javascript
jQuery学习笔记之2个小技巧
2015/01/19 Javascript
JavaScript中的包装对象介绍
2015/01/27 Javascript
JQuery中Ajax()的data参数类型实例分析
2015/12/15 Javascript
jQuery事件对象总结
2016/10/17 Javascript
AngularJs点击状态值改变背景色的实例
2017/12/18 Javascript
Angular实现的简单查询天气预报功能示例
2017/12/27 Javascript
使用vue的transition完成滑动过渡的示例代码
2018/06/25 Javascript
JQuery实现ajax请求的示例和注意事项
2018/12/10 jQuery
微信小程序云开发详细教程
2019/05/16 Javascript
ES6基础之字符串和函数的拓展详解
2019/08/22 Javascript
vue视频播放插件vue-video-player的具体使用方法
2019/11/08 Javascript
Nuxt默认模板、默认布局和自定义错误页面的实现
2020/05/11 Javascript
微信小程序canvas动态时钟
2020/10/22 Javascript
[44:15]DOTA2上海特级锦标赛主赛事日 - 5 败者组决赛Liquid VS EG第二局
2016/03/06 DOTA
Python创建xml的方法
2015/03/10 Python
Python中MySQLdb和torndb模块对MySQL的断连问题处理
2015/11/09 Python
Django实现web端tailf日志文件功能及实例详解
2019/07/28 Python
python-web根据元素属性进行定位的方法
2019/12/13 Python
Python 找出出现次数超过数组长度一半的元素实例
2020/05/11 Python
手把手教你将Flask应用封装成Docker服务的实现
2020/08/19 Python
基层党支部整改方案
2014/10/25 职场文书
廉政承诺书2015
2015/04/28 职场文书
交通安全月活动总结
2015/05/08 职场文书
2015年中学总务处工作总结
2015/07/22 职场文书
SQL Server2019数据库之简单子查询的具有方法
2021/04/27 SQL Server