JS脚本解析与执行顺序

在了解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()函数

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值