一、关于 setTimeout
setTimeout() 方法用于在指定的毫秒数后调用函数或计算表达式。
比如在1秒后打印出字母"a":
setTimeout('console.log("a")', 1000);
执行效果图:
我们看到执行setTimeout后,出现了一个数字 1309 ,这个数字是当前的setTimeout执行后所返回的一个唯一ID。
那么,这个唯一的ID的作用是什么呢?(请看下列代码)
var timer = setTimeout(function() {
console.log("a");
}, 1000);
clearTimeout(timer);
上述代码是我们,特别是前端小伙伴,再熟悉不过的了!
分成两块去看的话,那就是:
1. 设定定时器;
2. 清除定时器。
变量 timer 保存了当前这个 setTimeout 执行后的返回值,clearTimeout 接收了参数 timer ,就可以阻止setTimeout 的运行。
二、当 setTimeout 的延迟执行时间为 0
setTimeout的用法:
setTimeout(code / function, millseconds, param1, param2, . . .);
其中第一个参数是必要的,millseconds 为可选参数,默认为 0。
那么我们需要思考一个问题,
setTimeout(/* codes . . */, 1000);
延迟时间设为 1000,意味着1秒后执行。
那么,
setTimeout(/* codes . . */);
// 或者
setTimeout(/* codes . . */, 0);
是否就意味着一定会立即执行?
这个,我们用一个例子来验证下:
setTimeout(function() { console.log('setTimeout') } );
function a() {
console.log('函数 a 被执行!');
}
function b() {
console.log('函数 b 被执行!');
}
a();
b();
执行结果:
如上图所示,setTimeout 的参数 millseconds 设为 0 或为默认值,并不会使其立即执行,而是按照“先入先出”的原则,在当前任务队列中的事件或者同步任务完成后,在予以执行。
三、setTimeout 与 闭包
在 MDN 中,闭包被定义为:函数和声明该函数的词法环境的组合。即:可以获取其他函数内部变量的函数。
这里需要加深理解的概念是“词法环境”。
关于 setTimeout 与 闭包,这里用一个例子加以说明。
利用 setTimeout 将 1、2、3三个数字,间隔一秒予以打印。
按照思路大致可以写成:
for (var i = 1; i <= 3; i++) {
setTimeout(function() {
console.log(i);
}, 1000 * i);
}
可能大家已经预料出,这段代码并不会打印出1、2、3,而是:
因为,根据 setTimeout 是在调用栈清空后才被执行的特点,在 setTimeout 执行前 i 的值已经变为 4 了,所以打印结果为 3 个 4。
那么,如何实现我们预期的效果?
利用闭包,将每个 i 的值保存在闭包中来给 setTimeout 访问:
for (var i = 1; i <= 3; i++) {
setTimeout((function(i) {
return function() {
console.log(i);
};
})(i), 1000 * i);
}
// 或者
for (var i = 1; i <= 3; i++) {
(function(i) {
setTimeout('console.log(' + i + ')', 1000 * i);
})(i);
}
效果如下: