Js中函数执行顺序

严格意义上来说,javascript没有多线程的概念,所有的程序都是单线程依次执行的。

1.什么是单线程?

    通俗点说,就是代码在执行过程中,另一段代码想要执行就必须等当前代码执行完成后才可以进行。

 for(var i=1;i<=3;i++){
     setTimeout(function(){
         console.log(i); //输出:4,4,4
     },0)
 }

    既然延时器时间设置为0,那么应该执行一遍循环就应该立即打印出一个i,但是最终的打印结果为:4,4,4。之所以会出现上面的结果,正是因为js代码是单线程应用。

    在执行过程中,先遇到for循环,for循环先进入线程。当i=1时,循环走到setTimeOut后,此时的for循环还没有执行完成,setTimeOut就会被放入一个地方(线程池)等待执行。此时for循环继续执行,当i=2时,for循环仍没有执行完,这时的setTimeOut仍会被放在线程池中等待执行……依次类推,直到for循环转完3遍后,for循环执行完了,此时线程空闲了,在线程池中等待执行的setTimeOut依次执行打印i,而for循环执行完成后,i变成了4,所以打印出了三个4。

    如果想要改变上面的状况可以运用以下代码:

//将var变为let
for(let i=1; i<=3; i++){
    setTimeOut(function(){
        console.log(i);  //输出的结果为1,2,3
    },0);
}
//用自执行函数进行包裹
for(var i=1; i<=3; i++){
    !function(i){
        setTimeOut(function(){
            console.log(i);  //输出的结果为1,2,3
        },0);
    }(i)
}

  1.for循环中的变量变成块儿作用域:

      因为for循环头部的let不仅将i绑定到for循环快中,事实上它将其重新绑定到循环体的每一次迭代中,确保上一次迭代结束的值重新被赋值。setTimeout里面的function()属于一个新的域,通过 var 定义的变量是无法传入到这个函数执行域中的,通过使用 let 来声明块变量,这时候变量就能作用于这个块,所以 function就能使用 i 这个变量了;这个匿名函数的参数作用域 和 for参数的作用域 不一样,是利用了这一点来完成的。这个匿名函数的作用域有点类似类的属性,是可以被内层方法使用的。

  2.立即函数就是立即执行无需等待回调,代码加载就立即执行

    使用立即执行函数,通过函数作用域可以保存变量的特性来将每次循环的变量 i 保存到函数中

  3.如果给立即执行函数return一个function,setTimeout函数执行的就是这个function

for (var i = 0; i < 5; i++) {
  setTimeout((function(i) {
    console.log(i);
    return function() {
        console.log('回调')
        console.log(i)
    }
  })(i), i * 1000);
}

  先执行立即函数,再进行回调

posted @ 2020-08-21 16:23  Judicious  阅读(873)  评论(0编辑  收藏  举报