setTimeout()用法速查 附:深入解析
1.先自己写了一个最简单的:
console.log('global');
setTimeout(()=>{
console.log('set');
})
console.log('global2');
输出global global2 set
是因为异步的队列与同步不同,即使延时设为0,依旧会在同步队列执行完后才会执行。
2.经典面试题
for (var i = 1;i <= 5;i ++) {
setTimeout(function timer() {
console.log(i)
},i * 1000)
}
for循环时setTimeout()不是立即执行的,它们的回调被push到了宏任务队列当中,而在执行任务队列里的回调函数时,变量i早已变成了6。那如何得到想要的结果呢?很简单,原理就是需要给循环中的setTimeout()创建一个闭包作用域,让它执行的时候找到的变量i是正确的。
解决方案
(1)引入IIFE
for(var i = 0;i<5;i ++) {
(function(i){
setTimeout(function timer() {
console.log(i)
}, i * 1000);
})(i);
}
(2)利用ES 6引入的let
关键字
for(let i = 0;i<5;i++) {
setTimeout(function timer(){
console.log(i);
}, i * 1000);
}
for 循环头部的let 声明还会有一个特殊的行为。这个行为指出变量在循环过程中不止被声明一次,每次迭代都会声明。随后的每个迭代都会使用上一个迭代结束时的值来初始化这个变量。
(3)利用ES 5引入的bind函数
for (var i=1; i<=5; i++) {
setTimeout( function timer(i) {
console.log(i);
}.bind(null,i), i*1000 );
}
(4)利用setTimeout第三个参数
for (var i=1; i<=5; i++) {
setTimeout( function timer(i) {
console.log(i);
}, i*1000,i );
}
注:setTimeout函数第三个参数及以后的参数都可以作为timer函数的参数。
(5)把setTimeout用一个方法单独出来形成闭包
var loop = function (i) {
setTimeout(function timer() {
console.log(i);
}, i*1000);
};
for (var i = 1;i <= 5; i++) {
loop(i);
}