理解JS脚本执行的过程

来源:互联网 发布:怎样成为一个网络作家 编辑:程序博客网 时间:2024/06/05 14:26

一、前言JavaScript脚本在页面上的执行顺序问题,一直是个令javascript初学者困惑的问题。接下来我将就这个问题做一比较全面的总结,希望对初学者有所帮助。本文从以下四个方面讲解javascript的执行顺序问题:
1)     HTML文件的生命周期
2)     JavaScript是如何嵌入到HTML文件中的?
3)     JavaScript在页面中的执行顺序
4)     如何改变JavaScript执行顺序


二、HTML文件的生命周期从浏览器向服务器提交链接请求开始,到关闭当前页面,释放DOM对象结束,要经历如下几个过程:
1)     浏览器 —>   服务器:链接请求提交
2)     浏览器 <-   服务器:资源响应
3)     浏览器加载HTML文档
4)     解析HTML标签
5)     当遇到特殊标签如:IMG、SRC等时,向服务器请求相应资源(重复1,2两个步骤)
6)     解析完所有HTML标签,此时完成页面加载
7)     用户,浏览器,服务器端三者交互操作
8)     页面关闭,释放DOM对象
下面这个实例描述了一个简单文档加载过程:
首先客户端发送请求:http://localhost:8080/index.html。实际上发送的数据是:
GET /index.html HTTP/1.1
Accept: */*
Accept-Language: en,zh-cn;q=0.5
UA-CPU: x86
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (MSIE 7.0; MSIE 7.0; Windows NT 5.1; InfoPath.1)
Host: localhost:8080
Connection: Keep-Alive
然后服务端把index.html文件发送给客户端:
<html>
<head>
<title>Welcome to BrainySoftware</title>
</head>
<body>
<img src="./images/logo1.gif">
<br>
Welcome to BrainySoftware.
<br>
<img src="./images/logo.gif">
<br>
Welcome to BrainySoftware.
</body>
</html>

接下来客户端解析index.html 文档,当他解析到特殊标签<img 的时候,向服务短发送请求:
GET /images/logo1.gif HTTP/1.1
Accept: */*
Referer: http://localhost:8080/index.html
Accept-Language: en,zh-cn;q=0.5
UA-CPU: x86
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (MSIE 7.0; MSIE 7.0; Windows NT 5.1; InfoPath.1)
Host: localhost:8080
Connection: Keep-Alive
服务端把图片在发送给客户端。
然后当他解析到新的特殊标签<img 的时候,再次发送请求:
GET /images/logo.gif HTTP/1.1
Accept: */*
Referer: http://localhost:8080/index.html
Accept-Language: en,zh-cn;q=0.5
UA-CPU: x86
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (MSIE 7.0; MSIE 7.0; Windows NT 5.1; InfoPath.1)
Host: localhost:8080
Connection: Keep-Alive
服务端把图片在发送给客户端。
如此往复,把整个文档显示出来。


三、在HTML中嵌入Javasript的方法直接在javascript代码放在标记对<script>和</script> 之间 由<script />标记的src属性制定外部的js文件放在事件处理程序中,比如:<p >点击我</p>作为URL的主体,这个URL使用特殊的javascript:协议,比如:<a >点击我</a>利用javascript本身的document.write()方法写入新的javascript代码利用Ajax异步获取javascript代码,然后执行 无所不能的Dom方法,这个我最早在Yahoo的前端代码中见到,非常厉害,也写的详细些:
     var oScript = document.createElement("script");//创建一个Script元素
     oScript.src = "my.js";//制定src属性
     document.getElementsByTagName("head")[0].appendChild(oScript);
     说明:my.js的内容会在oScript加入到文档中之后获得并执行。

第3种和第4种方法写入的javascript需要触发才能执行,所以除非特别设置,否则页面加载时不会执行。


四、javascript在页面的执行顺序页面上的javascript代码是HTML文档的一部分,所以javascript在页面装载时执行的顺序就是其引入标记<script />的出现顺序, <script/>标记里面的或者通过src引入的外部JS,都是按照其语句出现的顺序执行,而且执行过程是文档装载的一部分。每个脚本定义的全局变量和函数,都可以被后面执行的脚本所调用。 变量的调用,必须是前面已经声明,否则获取的变量值是undefined。

<script type="text/javscrpt">//<![CDATA[
alert(tmp); //输出 undefined
var tmp = 1;
alert(tmp); //输出 1
         //]]></script>
同一段脚本,函数定义可以出现在函数调用的后面,但是如果是分别在两段代码,且函数调用在第一段代码中,则会报函数未定义错误。 <script type="text/javscrpt">//<![CDATA[
aa();             //浏览器报错
//]]></script>
<script type="text/javscrpt">//<![CDATA[
aa();                       //输出 1
function aa(){alert(1);}
//]]></script>
document.write()会把输出写入到脚本文档所在的位置,浏览器解析完documemt.write()所在文档内容后,继续解析document.write()输出的内容,然后在继续解析HTML文档。 <script type="text/javascript">//<![CDATA[
document.write('<script type="text/javascript" src="test.js"><//script>');
     document.write('<script type="text/javascript">');
     document.write('alert(2);')
     document.write('alert("我是" + tmpStr);');
     document.write('<//script>');
     //]]></script>
<script type="text/javascript">//<![CDATA[
     alert(3);
     //]]></script>
test.js的内容是:
var tmpStr = 1;
     alert(tmpStr);
在Firefox和Opera中的弹出值的顺序是:1、2、我是1、3 在IE中弹出值的顺序是:2、1、3,同时浏览器报错:tmpStr未定义

原因可能是IE在document.write时,并未等待加载SRC中的javascript代码完毕后,才执行下一行,所以导致2先弹出,并且执行到document.write(’document.write("我是" +tmpStr)’)调用tmpStr时,tmpStr并未定义,从而报错。
解决这个问题,可以利用HTML解析是解析完一个HTML标签,再执行下一个的原理,把代码拆分来实现:
<script type="text/javascript">//<![CDATA[
     document.write('<script type="text/javascript" src="test.js"><//script>');
     //]]></script>
<script type="text/javascript">//<![CDATA[
     document.write('<script type="text/javascript">');
     document.write('alert(2);')
     document.write('alert("我是" + tmpStr);');
     document.write('<//script>');
     //]]></script>
<script type="text/javascript">//<![CDATA[
     alert(3);
     //]]></script>
这样IE下和其他浏览器输出值的顺序都是一直的了:1、2、我是1、3。


五、如何改变javascript在页面的执行顺序利用onload

<script type="text/javascript">//<![CDATA[
window.onload = f;
function f(){alert(1);}
alert(2);
//]]></script>
输出值顺序是 2、1。
需要注意的是,如果存在多个winodws.onload的话,只有最有一个生效,解决这个办法是:
window.onload = function(){f();f1();f2();.....}
利用2级DOM事件类型
if(document.addEventListener){
window.addEventListener('load',f,false);
window.addEventListener('load',f1,false);
...
}else{
window.attachEvent('onload',f);
window.attachEvent('onload',f1);
...
}
IE中可以利用deferdefer作用是把代码加载下来,并不立即执行,等文档装载完毕之后再执行,有点类似onload,但是没有onload那样的局限性,可以重复使用,但是只在IE中有效,所以上面的例子可以修改成为

<script type="text/javascript">//<![CDATA[
document.write('<script type="text/javascript" src="test.js"><//script>');
document.write('<script type="text/javascript" defer="defer">');
document.write('alert(2);')
document.write('alert("我是" + tmpStr);');
document.write('<//script>');
//]]></script>
<script type="text/javascript">//<![CDATA[
alert(3);
//]]></script>
这样IE就不报错了,输出值的顺序变成:1、3、2、我是1
利用Ajax。
使用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,切没有//开头的注释。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 狗一有动静就叫怎么办 楼上天天闹动静怎么办 喝了奶茶失眠怎么办 失眠一宿第二天怎么办 睡觉外面噪音大怎么办 怀孕早期晚上睡不着怎么办 短发发尾翘怎么办 很累就是睡不着怎么办 人累但是睡不着怎么办 如果晚上睡不着该怎么办 晚上睡不着觉该怎么办 晚上睡不着该怎么办呢 晚上失眠睡不着该怎么办 晚上一直睡不着该怎么办 怀孕晚上睡不着该怎么办 运动太累睡不着怎么办 运动完睡不着觉怎么办 晚上冷得睡不着怎么办 晚上脚冷睡不着怎么办 短发头发有点乱怎么办 不想让别人睡觉怎么办 15岁晚上睡不着怎么办 16岁青少年失眠怎么办 好累又睡不着怎么办 造口患者拉肚子怎么办? 起床后头发乱怎么办 新生儿睡觉偏头怎么办 婴儿睡觉偏头怎么办 月经期间血下不来怎么办 月经下不来怎么办一点点咖啡色 突然早睡睡不着怎么办 移植后睡不着觉怎么办 孕期喜欢右侧睡怎么办 减肥期间有饭局怎么办 减肥期间晚上聚餐怎么办 减肥中遇到聚餐怎么办 减肥期间遭遇聚餐怎么办? 减肥期间聚会了怎么办 小猫摔到腿了怎么办 晚上睡觉颈椎痛怎么办 孕妇胎儿腿短怎么办