JS执行顺序


ContractedBlock.gif ExpandedBlockStart.gif Code
Code
<script>  //代码一  运行结果?
     TestFun();
    
function TestFun(){
    alert(
"Good Boy!");
    }
</script>

<script>  //代码二  运行结果?
      TestFun();
     
var TestFun = function(){
         alert(
"Good Boy!");
     }
</script>

例子2:

Code
<script>
function test(){
    alert(
0);
}
test();   
//提示信息是?

var test = function(){
    alert(
1);
}
test();  
//提示信息是?

var test = function(){
    alert(
2);
}
test();  
//提示信息是?

function test(){
    alert(
3);
}
test();  
//提示信息是?
</script>

 

 

 

全面解析各种浏览器对网页中JS代码的执行顺序2009/05/22 09:53        近来我通过一些测试以全面的解析网页在各种浏览器中的JavaScript代码的执行顺序,在这儿做个记录。
        我们知道javaScript是一种解释型语言,他的执行是自上而下,但是各个浏览器对于至上而下的理解是有细微差别的,而代码的上下游也就是程序流又对于程序正确至关重要,所以我觉得有必要深入理解多个js块儿的执行顺序。

首先得知道有多少方法能把javaScript加入到页面中呢?常见下述的前2种,其实还有更多。
1.页面中直接引入外部js文件:
< script  src ="my.js" ></ script >

2.页面中直接写如js片段
< script > alert( 1 ) </ script >

3.在js中引入js文件document.write("
< scr "+"ipt src ='my.js' ></ scr"+"ipt > ");
    注意:这时候"..
</ script > "必须拆成" </ scr"+"ipt > ",否则浏览器可能会把父js片段关闭掉,出错;
    
4.同样在js中引用其他js片段,document.write("
< scr "+"ipt > alert(1) </ scr"+"ipt > ");
    你可能觉得这个并没有必要,既然已经在script中了还套一层干嘛?呵呵,怎么说也是一种写法,而且它具有其特殊的行为,稍后我们讨论到。

5.使用Ajax中的xmlHttpRequest结合eval()来引入js,我最早在Dojo的代码见到,写的详细些:
    var ajaxRequest = getXmlHttpRequest()//省去各个浏览器得到xmlHttpRequest的部门
    ajaxRequest.open("GET","my.js",false);//使用xmlHttpRequest对象Get方法的同步调用
    ajaxRequest.send(null);
    sJsFragment = ajax.responseText;//得到字符串为js片段
    eval(sJsFragment);//执行js片段
    注意:这里要求my.js即后来的sJsFragment内容得是非常规范的js,切没有//开头的注释,怎样检查js是否规范呢?去http://www.jslint.com/
    
6.无所不能的Dom方法,这个我最早在Yahoo的前端代码中见到,非常厉害,也写的详细些:
    var oScript = document.createElement("script");//创建一个Script元素
    oScript.src = "my.js";//制定src属性
    document.getElementsByTagName("head")[0].appendChild(oScript);
    说明:my.js的内容会在oScript加入到文档中之后获得并执行。仔细看下这段容易发现这个调用是异步的,可以在文档载入之后通过事件触发,我用它变通了一下,作为了xmlHttpRequest的Get方法在跨域取数时的替代,获得了很完美的效果,以后有机会专门写篇文。
    
六种不少吧,可能还会有吧,而且这几种之间还可能相互嵌套,变化无常。
其中1、2、4、6种方式引入的javaScript的执行顺序是非常自然的,随着页面的载入以及后续的事件触发,它们遵守先来后到、而其内部自上而下。

我们主要关注的是第3、4种引入js方法带来的问题
测试准备:
编写文件1.js内容只有一行:
    alert("1.1");
编写文件3.js内容只有一行:
    alert("3.1");
再编写test.html
    
< html >
        
< head >         
            
< script > // 按第2种方式引入的脚本
                document.write( " <scr " + " ipt>alert(4.1);</scr " + " ipt> " ); // 按第4种方式引入的第一个脚本
                alert( 2.1 );
                document.write(
" <scr " + " ipt>alert(4.2);</scr " + " ipt> " ); // 按第4种方式引入的第二个脚本
                document.write( " <scr " + " ipt src='3.js'></scr " + " ipt> " ); // 按第3种方式引入的脚本
                document.write( " <scr " + " ipt>alert(4.3);</scr " + " ipt> " ); // 按第4种方式引入的第三个脚本
                alert( 2.2 );
            
</ script >
            
< script  src ="1.js" > // 按第1种方式引入的脚本</script>
         < / head>
         < body >
        
< / body>
     < / html>

执行结果:
IE浏览器的alert顺序为:       
4.1   -   2.1   -   4.2   -   4.3   -   2.2   -   3.1   -   1.1
FireFox浏览器的alert顺序为: 
4.1   -   2.1   -   4.2   -   2.2   -   3.1   -   4.3   -   1.1
Opera浏览器的alert顺序为:    
4.1   -   2.1   -   4.2   -   3.1   -   4.3   -   2.2   -   1.1

分析:
IE:把第3种方式引入的js文件放在当前脚本单元之后接着执行,把第4种方式引入的js当作宿主脚本单元的一部分,在内部其引入的位置执行。
Opera:把第3种和第4种方式引入的js都当作宿主脚本单元的一部分,在内部其引入的位置执行。
FireFox:第3种方式引入的js文件放在当前脚本单元之后接着执行;在宿主引入第3种脚本之前,把第4种方式引入的js当作宿主脚本单元的一部分,在内部其引入的位置执行;在宿主引入第3种脚本之后,把第4种方式引入的js当作单独的一个脚本块儿,在宿主脚本执行之后接着执行。FirefFox的这种做法是很不友好。

结论:
浏览器差别巨大,所以不要指望通过第3、4种方式引入的脚本在引入位置或者宿主脚本执行后执行,如果你要至少支持FireFox浏览器,那么通过这种逻辑控制程序流会有大麻烦,应该避免。

实例:
以发布Alimama的广告代码为例(google adsense、yahoo定向推广也一样)。
多数站CMS系统管理广告代码,常常需要js的方式来做代码调用。这样如果想通过一个js发布多块儿广告位就会出现麻烦,比如在一个js中:
第一种写法:
/ 发布第一块儿广告
var  alimama_pid = xxxx_1;
document.write(
" <scr " + " ipt src='http://p.alimama.com/inf.js'></scr " + " ipt> " );
// 发布第二块儿广告
var  alimama_pid = xxxx_2;
document.write(
" <scr " + " ipt src='http://p.alimama.com/inf.js'></scr " + " ipt> " );
希望引入的js块和js文件按书写顺序执行,根据上述测试的结论,针对这个任务,IE和FireFox是得不到想要的结果的,Opera可以。

第二种写法:
// 发布第一块儿广告
document.write( " <scr " + " ipt>var alimama_pid=xxxx_1</scr " + " ipt> " );
document.write(
" <scr " + " ipt src='http://p.alimama.com/inf.js'></scr " + " ipt> " );
// 发布第二块儿广告
document.write( " <scr " + " ipt>var alimama_pid=xxxx_2</scr " + " ipt> " );
document.write(
" <scr " + " ipt src='http://p.alimama.com/inf.js'></scr " + " ipt> " );
仍然根据上述测试的结论,IE是得不到想要的结果的,Opera干得很漂亮,而且蹩脚的FireFox居然也可以。

再说一个关于setTimeout()控制程序流的问题
下面一段脚本在页面加载时执行
function  fn(){
    alert(
" a " );
}
alert(
1 );
window.setTimeout(fn,
3000 );
alert(
2 );

各种浏览器alert的顺序都是1 
-   2   -  a。
也就是说setTimeout()方法不会让程序流停止,等候指定时间后再执行其下的语句,而只是告诉浏览器要在指定时间后执行参数中的方法。所以在程序载入过程中,不要指望setTimeout来造成程序流等待。

最后再补充一下又是一个关于js 执行顺序,执行入口的问题。
大家习惯于在window或者body上加上onload事件,在页面完全载入之后做一些操作。
因为,在页面没有载入完全之前去访问某些页面元素可能访问不到从而造成错误。
但这业务系统来讲是没有问题,而对于网站页面却不适合。
为什么呢?
因为常常并非网站页面的所有内容都是出于站内,你投放了广告代码、布了第三方的统计代码、调用了Alexa排名显示等等。
而这些js、iframe都是在其他域下,一旦这些js或者iframe的载入出现等待,那么你的onload事件将不会被调用,可能造成页面主逻辑受阻。

怎么解决?
如果你想访问页面元素,就把js写在元素所在位置之下即可。只是要注意不要写在被访问元素内部。
这也符合Yahoo Yslow高性能网站的一条规则Put Scripts at the Bottom。
 

 

转载于:https://www.cnblogs.com/mlaaalm/archive/2009/09/30/1577069.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值