如何确保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 相关文章推荐
NiftyCube——轻松实现圆角边框
Feb 20 Javascript
js中键盘事件实例简析
Jan 10 Javascript
jquery滚动特效集锦
Jun 03 Javascript
jquery实现点击弹出带标题栏的弹出层(从右上角飞入)效果
Sep 19 Javascript
JavaScritp添加url参数并将参数加入到url中及更改url参数的方法
Oct 26 Javascript
特殊日期提示功能的实现方法
Jun 16 Javascript
JavaScript探测CSS动画是否已经完成的方法
Aug 30 Javascript
使用AngularJS 跨站请求如何解决jsonp请求问题
Jan 16 Javascript
vue的状态管理模式vuex
Nov 30 Javascript
vue渲染时闪烁{{}}的问题及解决方法
Mar 28 Javascript
layui加载数据显示loading加载完成loading消失的实例代码
Sep 23 Javascript
微信小程序button标签open-type属性原理解析
Jan 21 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
开启CURL扩展,让服务器支持PHP curl函数(远程采集)
2011/03/19 PHP
PHP和Mysql中转UTF8编码问题汇总
2015/10/10 PHP
PHP常见字符串处理函数用法示例【转换,转义,截取,比较,查找,反转,切割】
2016/12/24 PHP
ExtJS 2.0实用简明教程 之获得ExtJS
2009/04/29 Javascript
js判断url是否有效的两种方法
2014/03/04 Javascript
js实现鼠标点击左上角滑动菜单效果代码
2015/09/06 Javascript
JavaScript实现字符串与日期的互相转换及日期的格式化
2016/03/07 Javascript
深入剖析JavaScript:Object类型
2016/05/10 Javascript
Bootstrap中datetimepicker使用小结
2016/12/28 Javascript
详解Angular 4.x 动态创建组件
2017/04/25 Javascript
详解vue2.0 transition 多个元素嵌套使用过渡
2017/06/19 Javascript
jQuery实现手势解锁密码特效
2017/08/14 jQuery
vue操作动画的记录animate.css实例代码
2019/04/26 Javascript
解决vue单页面应用打包后相对路径、绝对路径相关问题
2020/08/14 Javascript
Python实现把utf-8格式的文件转换成gbk格式的文件
2015/01/22 Python
解决python nohup linux 后台运行输出的问题
2018/05/11 Python
Python爬虫之网页图片抓取的方法
2018/07/16 Python
python正则表达式之对号入座篇
2018/07/24 Python
python实现朴素贝叶斯算法
2018/11/19 Python
详解Python3中ceil()函数用法
2019/02/19 Python
Python定时任务随机时间执行的实现方法
2019/08/14 Python
opencv实现简单人脸识别
2021/02/19 Python
tensorflow实现对张量数据的切片操作方式
2020/01/19 Python
pytorch 计算ConvTranspose1d输出特征大小方式
2020/06/23 Python
Python OpenCV读取中文路径图像的方法
2020/07/02 Python
python 两种方法修改文件的创建时间、修改时间、访问时间
2020/09/26 Python
世界上最好的威士忌和烈性酒购买网站:The Whisky Exchange
2016/11/20 全球购物
建筑专业自我鉴定
2013/10/22 职场文书
大学生毕业求职简历的自我评价
2013/10/24 职场文书
小学教育毕业生自荐信
2013/11/18 职场文书
《和田的维吾尔》教学反思
2014/04/14 职场文书
小学生倡议书范文
2014/05/13 职场文书
护理专业自荐书
2014/06/04 职场文书
合同和协议有什么区别?
2014/10/08 职场文书
校园新闻广播稿5篇
2014/10/10 职场文书
预备党员转正意见
2015/06/01 职场文书