JS 函数的执行时机--setTimeout

301 阅读2分钟

先来看看setTimeout的用法

setTimeout() 方法用于在指定的毫秒数后调用函数或计算表达式。

语法:

setTimeout(function, milliseconds, param1, param2, ...)
code/function必需。要调用一个代码串,也可以是一个函数。
milliseconds可选。执行或调用 code/function 需要等待的时间,以毫秒计。默认为 0。
param1, param2, ...可选。 传给执行函数的其他参数(IE9 及其更早版本不支持该参数)。

当执行下面这段代码的时候,会打出6个6:

let i = 0
for(i = 0; i<6; i++){
  setTimeout(()=>{
    console.log(i)
  },0)
}

原因是先执行完循环,i等于6,接着执行seTimeout,所以输出会是6,seTimeout和i++同在for循环内,所以一共执行了6遍,所以有了6个6的输出。

比较官方一点: 因为setTimeout是一个异步任务,执行到这里的操作会被浏览器丢到另一个任务队列里去, 浏览器这时候会继续执行for循环。每一次for循环的时候,setTimeout都执行一次,但是里面的函数没有被执行,而是被放到了任务队列里面,等待执行,for循环了6次,就放了6次,当主线程执行完成后,才进入任务队列里面执行。这时候因为for循环i=6了,所以输出的全部都是6。

就比方说你分别在今天晚上的8点、9点、10点、11点、12点、凌晨1点分别定了明天早上7点的闹钟,这6个闹钟无一例外的都会在明天的7点,同一时间响起。


要想写出让上面代码打印 0、1、2、3、4、5 的方法,可以把let放到for循环里面:

for(let i = 0;i = 0; i<6; i++){  setTimeout(()=>{
    console.log(i)
  },0)
}

因为let变量的作用域只能在当前函数中,所以每次for循环生成的都是一个新的i, setTimeout里输出的i就是这个新的i,这个i是不会变化的,所以输出的就是正常的。


其他方法

function numberNum(){
             var i = 6;
            var t = setInterval(function(){
                i--;
                console.log(i);
                if(i<=0){
                    clearInterval(t);
                }
            },1000);
         }