JS 函数的执行时机

295 阅读2分钟

要想知道 JS 会在什么时候执行我们的函数,我们需要了解下面几个概念

  • JS 事件队列
  • 宏任务与微任务的执行顺序
  • JS 函数只有在调用的时候,才能知道里面的代码到底是什么

那什么是事件队列?

简单说 JS 是单线程的,当它遇到setTimeout、ajax等异步任务时,会将这些异步任务放到异步处理模块,当这些异步任务达到触发条件(例如:setTimeout到达制定时间),异步任务的回调就会注册到任务队列中,任务队列又分宏任务队列和微任务队列(微任务队列只有一个),JS 引擎会优先执行微任务队列

来个栗子

for (var i = 0; i < 10; i++) {
    setTimeout(function () {
        console.log(i);
    }, 1000);
}
// 输出 10 个 10

我们本来是希望设置 10 个定时器,在一秒后打印 0~9 ,但现实和我们预计的不太一样,那是因为 for 循环是执行栈中同步执行的代码,而 setTimeout 是异步任务,所以它会被跳过,在同步任务结束之后才会被执行

// 上面的代码实际是这样的
for (var i = 0; i < 10; i++) {
    
}
// 当 for 循环结束时,i已经是 10 了
setTimeout(function () {
    console.log(i);
}, 1000);

解决方法

  1. 每次循环时将 i 当做传入,这里其实会产生10个闭包
for (var i = 0; i < 10; i++) {
    setTimeout(function (j) {
        console.log(j);
    }(i), 1000);
}
  1. 使用 let ,它会在每次循环产生单独的作用域,这里相当于声明的10个i
for (let i = 0; i < 10; i++) {
    setTimeout(function (){
        console.log(i);
    }, 1000);
}
  1. 设置 setTimeout 的第三个参数,其实第三个参数就是函数的传参,和第一种没区别
for (let i = 0; i < 10; i++) {
    setTimeout(function (j){
        console.log(j);
    }, 1000,i);
}

个人笔记,很乱,有可能不太对,以后学到再补充