JavaScript 中的 setTimeout() 函数具有以下特点和用法:
特点 | 描述 |
---|---|
延时执行 | setTimeout() 允许指定一段代码在调用后等待特定的毫秒数再执行,实现异步操作,避免阻塞主线程。 |
一次性执行 | 只保证回调函数至少在设定时间间隔后被执行一次;若需重复执行,须在回调内再次调用 setTimeout()。 |
非精确计时 | 由于 JavaScript 单线程和浏览器事件循环机制,实际执行时间可能晚于设定时间,尤其在 CPU 密集型任务或页面重排渲染期间。 |
返回值(timeoutID) | 调用 setTimeout() 后返回一个唯一的整数值,可用于 clearTimeout(timeoutID) 来取消未执行的任务。 |
用法示例
// 基本语法
setTimeout(function | code, milliseconds, [arg1, arg2, ...]);
// 示例
let timeoutID = setTimeout(function() {
console.log('这是延时一秒后的输出');
}, 1000);
// 或者使用箭头函数形式
let timeoutID2 = setTimeout(() => {
console.log('这也是延时一秒后的输出');
}, 1000);
// 如果需要向定时器函数传递参数
let timeoutID3 = setTimeout(function(name) {
console.log('你好,' + name);
}, 1000, '世界');
// 取消定时器
clearTimeout(timeoutID); // 取消由timeoutID标识的定时器
// 注意:如果要让某个函数按照固定周期执行,应该在一个函数中重新设置setTimeout而不是直接使用setInterval
function recurringFunction() {
// 执行某些操作...
setTimeout(recurringFunction, 1000);
}
recurringFunction(); // 开始每秒执行一次
常见问题
for (var i = 1; i <= 5; i++) {
setTimeout(function timer() {
console.log(i);
}, i * 1000);
}
// 输出 5 个 6,因为 setTimeout() 的回调函数在循环结束后才执行,此时 i 的值已经为 6。
这段代码,setTimeout()
函数内部访问的变量 i
是全局作用域中的 i
。由于 JavaScript 的异步执行机制和闭包特性,在 for
循环结束后,所有定时器回调函数实际上会引用同一个 i
变量,而非循环过程中每个迭代时的 i
值。
所以当定时器回调函数在各自设定的时间(1 秒、2 秒、3 秒、4 秒、5 秒后)依次执行时,它们都会打印出最后 for
循环结束时 i
的值,也就是 6。
如果期望输出从 1 到 5 的数字,需要利用闭包来捕获每次循环时的 i
值。可以使用 IIFE(立即调用的函数表达式)来实现:
for (var i = 1; i <= 5; i++) {
(function (i) {
setTimeout(function timer() {
console.log(i);
}, i * 1000);
})(i); // 这里将当前的 i 值传递给 IIFE,形成一个新的作用域
}
或者利用 ES6 的 let 块级作用域:
for (let i = 1; i <= 5; i++) {
setTimeout(function timer() {
console.log(i);
}, i * 1000);
}
当然,除了使用 IIFE 和 ES6 的 let
块级作用域之外,还可以利用 JavaScript 的 Function.prototype.bind()
方法来创建一个新的函数实例并绑定当前的 i
值。以下是使用 .bind()
的示例:
for (var i = 1; i <= 5; i++) {
setTimeout(
function timer(i) {
console.log(i);
}.bind(null, i),
i * 1000,
);
}
.bind()
方法会创建一个新的函数,并将其上下文(this
)和传入的参数预先绑定到新函数中,这样在定时器回调执行时就能正确捕获循环中的每个独立 i
值。
网友评论