JS的执行时机

80 阅读2分钟

JS的执行机制

  • JS执行机制示意图 ,主线程的执行环境栈上首先执行同步任务,然后再依靠Event Loop机制来不断循环将任务队列中的各个task放到执行环境栈中执行。
  • 同步任务:在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务。同步函数有顺序性,当一个同步函数被调用时,该函数不会立即返回,直到规定的操作全部完成后该函数才会返回。
  • 异步任务:不进入主线程,某个异步任务可以执行了,该任务就会进入主线程执行。异步函数无顺序性,当一个异步函数被调用时,该函数会立即返回,尽管该函数规定的操作任务还未完成。
  • JS的执行时机不同,得到的结果也不同。

JS执行时机实例

为什么下段代码会打出6个6

let i = 0
for(i=0;i<6;i++){
    setTimeout(()=>{
        console.log(i)
    },0)
}
// 6个6
  • for循环原本的执行步骤是:先让i等于 0 ,然后判断i是否小于6,若是,则执行setTimeout稍后打印出i的值,再执行i++;若不是,则循环结束。
  • 由于setTimeout的异步延时操作(且不会阻碍for循环的执行),将原本要立马打出来的结果延迟到整个for循环结束之后再执行。因此i的值并不会在每一次的for循环中被打出,而是会等整个for循环结束之后再一起打出。这样每执行一次for循环,就会有一个i的值会被打出被放进任务队列中,不会立即执行console.log(i)。到最后for循环总共执行了6次,i=6,有6个i的值被打出来,即连续打出6个6。

如何打出0-5

  • let放进for循环里,让let变量的作用域只在当前函数中,每次for循环的都是一个新的变量i,因此setTimeout里面的i是不同的变量,这样可视作每次i的值都是一次完整的函数执行。
for(let i=0;i<6;i++){
    setTimeout(()=>{
        console.log(i)
    },0)
}
// 0 1 2 3 4 5
  • 采用闭包
let i 
for(i = 0; i<6; i++){
  !function(x){
      setTimeout(()=>{
        console.log(x)
      },0)
  }(i)
}
// 0 1 2 3 4 5

参考:彻底弄懂 JavaScript 执行机制