JS脚本解析与执行顺序

来源:互联网 发布:淘宝二手可信吗 编辑:程序博客网 时间:2024/05/22 03:10

在了解JavaScript具体是怎样解析之前,我们先来了解几个重要的概念:

1.代码块

JavaScript中的代码块是指由

<script type="text/javascript">       alert("这是代码块一");</script><script type="text/javascript">       alert("这是代码块二");</script>

JS是按照代码块来进行编译和执行的,代码块间相互独立,但变量和方法共享。

浏览器在解析html文档流的时候,如果遇到一个<script>标签,则JS会等到这个代码块加载完之后再对代码进行预编译,然后再执行。执行完毕后,浏览器会继续解析html文档流,同时js也准备好处理下一个代码块。由于JS是按块执行的,因此在一个JS块中调用后面声明的变量或者函数就会提示语法错误。但是不同块都属于一个全局作用域,也就是说,块之间的变量和函数可以共享。
举例:

<title>JS执行顺序</title>    <script type="text/javascript">        alert("这是代码块1");//先弹出"这是代码块1"        alert(str);//因为str没有定义,所以浏览器会报错,后面代码不能运行        alert("haha");        var test = "我是代码块一中的变量";    </script>    <script type="text/javascript">        alert("我是代码块二");//弹出"我是代码块二"        alert(test);//弹出"我是代码块一中的变量"    </script>

代码块一运行报错,但是不影响代码块二的执行,这就是代码块间的独立性,而代码块二能调用到代码块一中的=变量,即为块间的共享性。

2.函数声明与函数赋值

JS函数定义分为两种:韩顺声明和函数赋值式。

<script type="text/javascript">  function Fn(){    //函数声明 }       var Fn = function(){   //赋值式函数 }</script>

这两者在JS的与编译器的区别会体现出来。下面就来说一说预编译。

3.预编译器与执行期

JS的解析分为两个阶段:预编译期(预处理期)与执行期
预编译期JS会对本代码中所有声明的变量和函数进行处理(类似于c语言的编译),但是处理函数只是处理声明式函数,将其提前,而变量也只是进行了声明但是并未进行初始胡以及赋值。
举例:

<script type="text/javascript">  Fn();//"执行了声明式函数",在预编译期函数被处理了  function Fn(){//声明式函数     alert(""执行了声明式函数);  }       var Fn = function(){//赋值式函数     alert("执行了赋值式函数");  }</script>

了解了以上几个概念,下面来看一个例子:

    <script type="text/javascript">        Fn();//Fn is not defined    </script>    <script type="text/javascript">        function Fn(){            alert("执行了函数1");        }    </script>

代码块一在执行函数Fn时报错,这是为什么?
原因在于JS引擎是按照代码块来顺序执行的,完整的说是按照代码块来进行预处理和执行的,也就是预处理的只是执行到代码块的声明函数和变量,对于还未加载的代码块,没有办法进行预处理。

JS是单线程的

举例:

function foo(){  console.log("first");  setTimeout((function(){console.log('second');}),5);}for(var i = 0;i<10000000;i++){    foo();}

执行结果会首先会全部输出first,然后全部输出second.
JS运行在浏览器中是单线程的,每一个window的一个JS线程,既然是单线程的,在某个特定的时刻,只有特定的代码能够执行,并且阻塞其他代码的执行。而浏览器是事件驱动的,浏览器中很多行为是异步的,会创建事件放在执行队列中。Javascript引擎是单线程处理它的任务队列,所以当多个事件触发时,会依次放入队列,然后一个个响应(所以上面的代码是5ms后把输出second的任务加入队列中),而当前有任务,所以只能等到1000000个first输出完成后才会输出second。

浏览器是多线程的

虽然JS运行在浏览器中,是单线程的,但是浏览器不是单线程的。浏览器中的很多异步行为都是由浏览器新开一个线程去完成的。Javascript引擎线程是浏览器多个线程中的一个,它本身是单线程的。浏览器还包括很多其他线程,如界面渲染线程,浏览器事件触发线程,Http请求线程等。
所谓的javascript是单线程的,是指javascript运行在浏览器中是单线程的,叫做javascript引擎线程。

下面这个例子会让我们差生怀疑,产生一种JS是多线程的错觉:

function fn1(){   setTimeout(function(){    alert("我先调用")},1000);}function fn2(){  alert("我后调用");}fn1();fn2();//先弹出:"我后调用"//1s后弹出:"我先调用"

看上去,fn2()和延时程序是分两个程序走,但其实,这是JS的“回调”机制在起作用,类似于操作系统中的“中断和响应”——延时程序设置一个“中断”,然后执行fn2(),等待1000ms之后,再回调执行函数fn1()。
下面这个例子也是JS回调函数的实例:

<script type="text/javascript"> function fnOnLoad(){ alert("I am outside the Wall!"); } </script> <body onload="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加载完成之后,回调执行fnOnLoad()函数

原创粉丝点击