js 程序执行与顺序实现详解

声明:这是转载的

原帖地址:http://www.jb51.net/article/36755.htm

JavaScript是一种描述型脚本语言,由浏览器进行动态的解析与执行,浏览器对于不同的方式有不同的解析顺序,详细介绍如下,感兴趣的朋友可以参考下哈
函数的声明和调用 
JavaScript是一种描述型脚本语言,由浏览器进行动态的解析与执行。函数的定义方式大体有以下两种,浏览器对于不同的方式有不同的解析顺序。 
代码如下: 
复制代码代码如下:

//“定义式”函数定义 
function Fn1(){ 
alert("Hello World!"); 

//“赋值式”函数定义 
var Fn2 = function(){ 
alert("Hello wild!"); 


页面加载过程中,浏览器会对页面上或载入的每个js代码块(或文件)进行扫描,如果遇到定义式函数,则进行预处理(类似于C等的编译),处理完成之后再开始由上至下执行;遇到赋值式函数,则只是将函数赋给一个变量,不进行预处理(类似1中变量必须先定义后引用的原则),待调用到的时候才进行处理。下面举个简单的例子: 
代码如下: 
复制代码代码如下:

//“定义式”函数定义 
Fn1(); 
function Fn1(){ 
alert("Hello World!"); 


正常执行,弹出“Hello World!”,浏览器对Fn1进行了预处理,再从Fn1();开始执行。 
代码如下: 
复制代码代码如下:

//“赋值式”函数定义 
Fn2(); 
var Fn2 = function(){ 
alert("Hello wild!"); 


Firebug报错:Fn2 is not a function,浏览器未对Fn2进行预处理,依序执行,所以报错Fn2未定义。 

3. 代码块及js文件的处理 
“代码块”是指一对<script type=”text/网页特效”></script>标签包裹着的js代码,文件就是指文件啦,废话:D 
浏览器对每个块或文件进行独立的扫描,然后对全局的代码进行顺序执行(2中讲到了)。所以,在一个块(文件)中,函数可以在调用之后进行“定义式”定义;但在两个块中,定义函数所在的块必须在函数被调用的块之前。 
很绕口,看例子好了: 
代码如下: 
复制代码代码如下:

<script type="text/javascript"> 
Fn(); 
</script> 
<script type="text/javascript"> 
function Fn(){ 
alert("Hello World!"); 

</script> 
// 报错:Fn is notdefined,两个块换过来就对了 

4. 重复定义函数会覆盖前面的定义 
这和变量的重复定义是一样的,代码: 
代码如下: 
复制代码代码如下:

function fn(){ 
alert(1); 

function fn(){ 
alert(2); 

fn(); 
// 弹出:“2” 

如果是这样呢: 
代码如下: 
复制代码代码如下:

fn(); 
function fn(){ 
alert(1); 

function fn(){ 
alert(2); 

// 还是弹出:“2” 

还是弹出“2”,为什么?2都讲了好吧… 

5. body的onload函数与body内部函数的执行 
body内部的函数会先于onload的函数执行,测试代码: 
代码如下: 
复制代码代码如下:

//html head... 
<script type="text/javascript"> 
function fnOnLoad(){ 
alert("I am outside the Wall!"); 

</script> 
<body οnlοad="fnOnLoad();"> 
<script type="text/javascript"> 
alert("I am inside the Wall.."); 
</script> 
</body> 
//先弹出“I am inside the Wall..”; 
//后弹出“I am outside the Wall!” 

body的onload事件触发条件是body内容加载完成,而body中的js代码会在这一事件触发之前运行(为什么呢?6告诉你..) 

6. JavaScript是多线程or单线程? 
严格来说,JavaScript是没有多线程概念的,所有的程序都是“单线程”依次执行的。 
举个不太恰当的例子: 
代码如下: 
复制代码代码如下:

function fn1(){ 
var sum = 0; 
for(var ind=0; ind<1000; ind++) { 
sum += ind; 

alert("答案是"+sum); 

function fn2(){ 
alert("早知道了,我就是不说"); 

fn1(); 
fn2(); 

//先弹出:“答案是499500”, 
//后弹出:“早知道了,我就是不说” 

那你肯定要问:那延时执行、Ajax异步加载,不是多线程的吗?没错,下面这样的程序确实看起来像“多线程”: 
代码如下: 
复制代码代码如下:

function fn1(){ 
setTimeout(function(){ 
alert("我先调用") 
},1000); 

function fn2(){ 
alert("我后调用"); 

fn1(); 
fn2(); 
// 先弹出:“我后调用”, 
// 1秒后弹出:“我先调用” 

看上去,fn2()和延时程序是分两个过程再走,但其实,这是JavaScript中的“回调”机制在起作用,类似于操作系统中的“中断和响应” —— 延时程序设置一个“中断”,然后执行fn2(),待1000毫秒时间到后,再回调执行fn1()。 
同样,5中body的onload事件调用的函数,也是利用了回调机制——body加载完成之后,回调执行fnOnLoad()函数。 
Ajax请求中的数据处理函数也是一样的道理。 
关于JavaScript线程问题的更深入讨论,看这篇 javascript中的线程之我见,以及infoQ上的 JavaScript多线程编程简介。 
困了,再说一下回调函数吧。 

7. 回调函数 
回调函数是干嘛用的?就是回调执行的函数嘛,又废话:D 
如6所说,最常见的回调就是onclick、onmouseo教程ver、onmousedown、onload等等浏览器事件的调用函数;还有Ajax异步请求数据的处理函数;setTimeOut延时执行、setInterval循环执行的函数等。 
干脆我们写一个纯粹的回调函数玩: 
代码如下: 
复制代码代码如下:

function onBack(num){ 
alert("姗姗我来迟了"); 
// 执行num个耳光 

function dating(hours, callBack){ 
var SP= 0; // SP,愤怒值 
//女猪脚在雪里站了hours个钟头 
//循环开始.. 
SP ++; 
//循环结束... 
callBack(SP); 

dating(1, onBack); 


二 浏览器加载渲染网页过程解析

浏览器的工作机制,一句话概括起来就是:web浏览器与web服务器之间通过HTTP协议进行通信的过程。所以,C/S之间握手的协议就是HTTP协议。浏览器接收完毕开始渲染之前大致过程如下:


从浏览器地址栏的请求链接开始,浏览器通过DNS解析查到域名映射的IP地址,成功之后浏览器端向此IP地址取得连接,成功连接之后,浏览器端将请 求头信息 通过HTTP协议向此IP地址所在服务器发起请求,服务器接受到请求之后等待处理,最后向浏览器端发回响应,此时在HTTP协议下,浏览器从服务器接收到 text/html类型的代码,浏览器开始显示此html,并获取其中内嵌资源地址,然后浏览器再发起请求来获取这些资源,并在浏览器的html中显示。

离我们最近并能直接显示一个完整通信过程的工具就是Firebug了,看下图:

浏览器加载渲染网页过程解析 - 落枫loven - SEO|网络营销|百度竞价 - 林宗辉
 


其中黄色的tips浮层告诉了我们”colorBox.html”从发起请求到关闭连接整个过程中每个环节的时长(域名解析 -> 建立连接 -> 发起请求 -> 等待响应 -> 接收数据),点击该请求,可以获得HTTP的headers信息,包含响应头信息与请求头信息,如:
//响应头信息 HTTP/1.1 304 Not Modified Date: Wed, 02 Mar 2011 08:20:06 GMT Server: Apache/2.2.4 (Win32) PHP/5.2.1 Connection: Keep-Alive Keep-Alive: timeout=5, max=100 Etag: "1e483-1324-a86f5621"
//请求头信息 GET /Docs/eva/api/colorBox.html HTTP/1.1 Host: ued.com User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-cn,zh;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: GB2312,utf-8;q=0.7,*;q=0.7 Keep-Alive: 115 Connection: keep-alive Referer: http://ued.com/Docs/ If-Modified-Since: Thu, 17 Feb 2011 10:14:07 GMT If-None-Match: "1e483-1324-a86f5621" Cache-Control: max-age=0

另外,ajax异步请求同样遵循HTTP协议,原理大同小异。

浏览器加载显示html页面内容的顺序

我们经常看到浏览器在加载某个页面时,部分内容先显示出来,又有些内容后显示。那么浏览器加载显示html究竟是按什么顺序进行的呢?

其实浏览器加载显示html的顺序是按下面的顺序进行的:
1、IE下载的顺序是从上到下,渲染的顺序也是从上到下,下载和渲染是同时进行的。
2、在渲染到页面的某一部分时,其上面的所有部分都已经下载完成(并不是说所有相关联的元素都已经下载完)。
3、如果遇到语义解释性的标签嵌入文件(JS脚本,CSS 剑 敲创耸盜E的下载过程会启用单独连接进行下载。
4、并且在下载后进行解析,解析过程中,停止页面所有往下元素的下载。
5、样式表在下载完成后,将和以前下载的所有样式表一起进行解析,解析完成后,将对此前所有元素(含以前已经渲染的)重新进行渲染。
6、JS、CSS中如有重定义,后定义函数将覆盖前定义函数。

Firefox处理下载和渲染顺序大体相同,只是在细微之处有些差别,例如:iframe的渲染

如果你的网页比较大,希望部分内容先显示出来,粘住浏览者,那么你可以按照上面的规则合理的布局你的网页,达到预期的目的。

 JS的加载
不能并行下载和解析(阻塞下载)
当 引用了JS的时候,浏览器发送1个jsrequest就会一直等待该request的返回。因为浏览器需要1个稳定的DOM树结构,而JS中很有可能有代 码直接改变了DOM树结构,比如使用 document.write 或 appendChild,甚至是直接使用的location.href进行跳转,浏览器为了防止出现JS修改DOM树,需要重新构建DOM树的情况,所以 就会阻塞其他的下载和呈现.

 

  为了更清楚的显示页面元素的加载顺序,动手写了一个程序,程序对页面中的每个元素都延迟10秒。

程序的位置在见附件。

首先查看TestHtmlOrder.aspx这个页面,使用HttpWatcher来检测页面元素的加载。

从下面的图中可以看到加载顺序。


浏览器加载渲染网页过程解析 - 落枫loven - SEO|网络营销|百度竞价 - 林宗辉
 

IE首先加载了主页面TestHtmlOrder.aspx,

下载了主页面后,页面首先显示的是“红色剑灵”、“蓝色剑灵”几个字,但此时显示的是只是黑色字体,没有样式,因为样式还没有下载下来。

接下来页面中的标签是JS标签,属于嵌入文件,因此IE需要将其下载下来。这有两个文件,虽然IE同时能够和WebServer建立两个链接,但是此时并没有使用两个连接,而是使用一个连接,在下载完成后,接下来才下载另外一个文件。

究其原因,是因为JS包含了语法定义,在第二个文件里面的函数可能用到了第一个文件里面的变量和函数,IE没有办法判断,或者需要很耗时的判断,才 能判断文件下载的先后顺序。而在解释方面,IE对JS文件是下载一个,解释一个(可以执行文件TestJsOrder2.aspx)。如果先下载的是第二 个文件,此时就会发生解释错误。因此需要开发者自己在放置JS文件位置时,按先后顺序放好,IE依次下载进行解释。后面的函数覆盖前面的函数定义

在下载完成后,我们看到helloWorld,helloworld2,开始顺序执行。而此时字体的样式表和图片仍然没有下载下来。

在helloWorld,helloWorld2执行过程时,此时页面停留在函数执行的中断点(alert部分)。此时IE并没有去下载CSS的文件。由此说明JS函数的执行会阻塞IE的下载。

接下来我们看到CSS文件的下载也是使用了一个连接,也是串行下载。其串行下载的原因和JS串行下载原因是一样的。

在两个CSS文件下载过程中,我们看到“红色剑灵”,“蓝色剑灵”依次变为红色和蓝色,两者颜色的转换时间相差在10秒,说明样式文件和JS文件一样是下载完一个解析一个的。

现在转到TestCssOrder.aspx看一下,可以看到 开始时“红色剑灵”,“红色强壮剑灵”,显示为红色,过了10秒“蓝色剑灵”显示为蓝色,再过10秒,“红色强壮剑灵”字体变粗了,同时“红色强壮剑灵 2”开始出现。在刚开始“红色剑灵”,“红色强壮剑灵”显示红色时,第三个样式还没有下载下来,此时IE使用已经下载到样式对上面的元素渲染了一遍,此时 虽然“红色剑灵”,“红色强壮剑灵”样式定义不同,但是显示效果一样。第三个文件下载后,此时IE又重新对“红色强壮剑灵”渲染了一遍,此时其变为加粗, 以上所有的文件加载并且渲染完成后,开始渲染下面的标签“红色强壮剑灵2”

有一点需要证明:在IE使用样式对标签进行渲染时,是不是停止了其他页面元素的下载?原来我想通过加长渲染时间(利用滤镜,将标签元素数目增大)来检测,不过没有验证成功。只是从JS函数的执行推断CSS的渲染也是如此。

接下来看到的是图片文件下载,此时看到的是两个图片同时开始下载,而且是下载完成后,立即在页面上开始显示,直到所有的图片下载完成。

注:一个测试文件在网络传输上所花费时间的办法。

首先需要明白检测中w ait值的意义:wait = 服务器所花时间 + 网络时间

服务器所花时间我们可以用Thread.Sleep(10000);来让其休息10s,

比如这个:

浏览器加载渲染网页过程解析 - 落枫loven - SEO|网络营销|百度竞价 - 林宗辉
 

由此大概可以计算出 10.002-10 = 0.002秒,这就是大概在网络上所花的时间。



  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在for循环中,循环的执行顺序是按照循环条件和循环体中的语句顺序来确定的。首先,循环条件会被判断,如果条件为真,则执行循环体中的语句,然后再次判断循环条件,如果仍然为真,则再次执行循环体中的语句,以此类推,直到循环条件为假时,循环结束。\[2\] 在给出的代码示例中,第一个for循环的循环条件是a < 1,初始时a的值为0,因此循环条件为真,进入循环体,打印出a的值为0。然后再次判断循环条件,由于a的值仍然小于1,循环继续执行,再次打印出a的值为0。由于循环条件仍然为真,循环继续执行,但由于没有对a的值进行更新,循环陷入无限循环,直到程序被中断或者出现其他异常。 第二个for循环的循环条件是b < 1,初始时b的值为0,循环条件为真,进入循环体,打印出b的值为0。然后再次判断循环条件,由于b的值仍然小于1,循环继续执行,再次打印出b的值为0。由于循环条件仍然为真,循环继续执行,但与第一个for循环不同的是,这里使用的是前置递增运算符++b,所以b的值会在每次循环结束后加1。因此,循环体执行完毕后,b的值变为1,再次判断循环条件时,b的值已经不小于1,循环结束。\[2\] 总结起来,第一个for循环会陷入无限循环,而第二个for循环会执行一次循环体后结束。这是因为在第一个for循环中,循环条件始终为真,没有对循环变量a进行更新,导致循环无法终止。而在第二个for循环中,循环条件在第一次循环后变为假,循环终止。\[2\] #### 引用[.reference_title] - *1* *3* [Oracle的for循环执行顺序详解](https://blog.csdn.net/Albert_LG/article/details/111113860)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [深入理解for循环内部执行顺序(案例+详解)](https://blog.csdn.net/weixin_44407699/article/details/103280503)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值