for 循环里面使用 setTimeout

这是一道简单的 JS 面试题,在这里记录一下它的6种方法,共勉。

for(var i = 0; i < 5; i++) {
    setTimeout(() => {
        console.log(i)
    }, 1000)
}
console.log(i)
复制代码

输出结果:5 -> 5,5,5,5,5 (箭头表示1s,逗号表示几乎同时输出)

1. 借助 let 的暂时性死区

for(let i = 0; i < 5; i++) {
    setTimeout(() => {
        console.log(i)
    }, 1000)
}
console.log(i)
复制代码

输出结果:5 -> 0,1,2,3,4

2. 借助 setTimeout 的第三个参数

for(var i = 0; i < 5; i++) {
    setTimeout((j) => {
        console.log(j)
    }, 1000, i)
}
console.log(i)
复制代码

输出结果:5 -> 0,1,2,3,4

3. 借助立即执行函数

for(var i = 0; i < 5; i++) {
    ((j) => {
        setTimeout(() => {
            console.log(j)
        }, 1000)
    })(i)
}
console.log(i)
复制代码

输出结果:5 -> 0,1,2,3,4

4. 借助形参的特性

var sleepConsole = (i) => {
    setTimeout(() => {
        console.log(i)
    }, 1000)
}

for(var i = 0; i < 5; i++) {
    sleepConsole(i)  // i会被复制后传递
}

console.log(i)
复制代码

输出结果:5 -> 0,1,2,3,4

5. 借助 Promise

// 1.建立数组存储 Promise
const task = []

// 2.抽取方法生成异步操作
const output = (i) => new Promise(resolve => {
    setTimeout(() => {
        console.log(i)
        resolve()
    }, 1000 * i)
})

// 3.循环执行异步操作
for(var i = 0; i < 5; i++) {
    task.push(output(i))
}

// 4.异步操作执行完成后输出最后的i
Promise.all(task).then(() => {
    setTimeout(() => {
        console.log(i)
    }, 1000)
})
复制代码

输出结果:0 -> 1 -> 2 -> 3 -> 4 -> 5

6. 借助 async/await

// 生成休眠函数
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms))

(async () => {
    for(var i = 0; i < 5; i++) {
        if (i > 0) {
            await sleep(1000)
        }
        console.log(i)
    }
    await sleep(1000)
    console.log(i)
})()
复制代码

输出结果:0 -> 1 -> 2 -> 3 -> 4 -> 5

猜你喜欢

转载自juejin.im/post/7019233455645032455