如何确保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 相关文章推荐
Wordpress ThickBox 点击图片显示下一张图的修改方法
Dec 11 Javascript
利用jquery的获取JS文件中的字符串内容
Feb 14 Javascript
jQuery中map()方法用法实例
Jan 06 Javascript
js实现屏幕自适应局部代码分享
Jan 30 Javascript
jQuery实现信息提示框(带有圆角框与动画)效果
Aug 07 Javascript
JavaScript中for循环的几种写法与效率总结
Feb 03 Javascript
ES6下React组件的写法示例代码
May 04 Javascript
使用puppeteer破解极验的滑动验证码
Feb 24 Javascript
浏览器事件循环与vue nextTicket的实现
Apr 16 Javascript
微信小程序导入Vant报错VM292:1 thirdScriptError的解决方法
Aug 01 Javascript
利用JS代码自动删除稿件的普通弹幕功能
Sep 20 Javascript
Vue2项目中对百度地图的封装使用详解
Jun 16 Vue.js
如何确保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
饭制《星际争霸》Mod:优化游戏机制 增加新单位
2017/07/02 星际争霸
php中http与https跨域共享session的解决方法
2014/12/20 PHP
PHP获取文本框、密码域、按钮的值实例代码
2017/04/19 PHP
PHP支付宝当面付2.0代码
2018/12/21 PHP
php计数排序算法的实现代码(附四个实例代码)
2020/03/31 PHP
比较简单的异步加载JS文件的代码
2009/07/18 Javascript
JQuery扩展插件Validate 2通过参数设置验证规则
2011/09/05 Javascript
Javascript解析URL方法详解
2014/12/05 Javascript
javascript实现添加附件功能的方法
2015/11/18 Javascript
javascript实现保留两位小数的多种方法
2015/12/18 Javascript
jquery checkbox的相关操作总结
2016/10/17 Javascript
微信小程序开发教程-手势解锁实例
2017/01/06 Javascript
详解JavaScript树结构
2017/01/09 Javascript
浅谈Vue.js 组件中的v-on绑定自定义事件理解
2017/11/17 Javascript
微信小程序商品详情页的底部弹出框效果
2020/11/16 Javascript
javascript中this的用法实践分析
2019/07/29 Javascript
vuex actions异步修改状态的实例详解
2019/11/06 Javascript
[02:57]DOTA2亚洲邀请赛小组赛第四日 赛事回顾
2015/02/02 DOTA
[04:49]期待西雅图之战 2016国际邀请赛中国区预选赛WINGS战队赛后采访
2016/06/29 DOTA
Python文件打开方式实例详解【a、a+、r+、w+区别】
2019/03/30 Python
Python数据分析模块pandas用法详解
2019/09/04 Python
Python列表list常用内建函数实例小结
2019/10/22 Python
使用python实现画AR模型时序图
2019/11/20 Python
如何使用repr调试python程序
2020/02/28 Python
pycharm的python_stubs问题
2020/04/08 Python
Django扫码抽奖平台的配置过程详解
2021/01/14 Python
Free People中国官网:波西米亚风格女装服饰
2016/08/30 全球购物
Melijoe英国官网:法国儿童时尚网站
2016/11/18 全球购物
Unix控制后台进程都有哪些进程
2016/09/22 面试题
生物科学系大学生的自我评价
2013/12/20 职场文书
食品科学与工程专业毕业生求职信范文
2014/07/21 职场文书
医院领导班子查摆问题对照检查材料思想汇报
2014/10/08 职场文书
积极心理学课程心得体会
2016/01/22 职场文书
python3读取文件指定行的三种方法
2021/05/24 Python
小程序与后端Java接口交互实现HelloWorld入门
2021/07/09 Java/Android
JavaScript原型链中函数和对象的理解
2022/06/16 Javascript