Skip to content

JavaScript 定时器

JavaScript 可以在指定的延迟后或以固定的时间间隔执行代码。这些通常被称为定时器事件(timing events)或定时操作(timed operations)。

JavaScript 提供了内置函数,允许你安排代码的执行。你可以在经过一定时间后执行函数一次,或者以设定的间隔重复执行。

两个关键的方法是:

  • setTimeout(callbackFunction, delayInMilliseconds, arg1, arg2, ...):在经过 delayInMilliseconds 后,执行 callbackFunction 一次。可选参数 arg1, arg2, ... 将传递给回调函数。
  • setInterval(callbackFunction, intervalInMilliseconds, arg1, arg2, ...):重复执行 callbackFunction,每次执行之间间隔 intervalInMilliseconds。可选参数也会传递给回调函数。

注意:setInterval() 和 setTimeout() 在浏览器中是全局 window 对象的方法(在 Node.js 等环境中是全局作用域的方法)。在浏览器环境中,你无需 window. 前缀即可直接调用它们(例如,setTimeout(...))。

这些函数是非阻塞的(non-blocking)。这意味着 JavaScript 在等待定时器时不暂停;它可以继续执行其他代码。回调函数被添加到事件队列 (event queue) 中,并在定时器到期且 JavaScript 引擎的调用栈 (call stack) 为空(即主线程 free)时执行。

setInterval() 方法重复调用一个函数或执行一段代码片段,在每次调用之间有固定的时间延迟。

// 首选语法:传递函数引用
let intervalID = setInterval(myFunction, 2000);
// 匿名函数示例:
let intervalID_anon = setInterval(function() {
console.log("Executing every 2 seconds");
}, 2000);
// 箭头函数示例 (现代且简洁):
let intervalID_arrow = setInterval(() => {
console.log("Arrow function executing every 2 seconds");
}, 2000);
// 向回调函数传递参数:
function greet(name) {
console.log(`Hello, ${name}!`);
}
let greetInterval = setInterval(greet, 1500, "Alice");
// 要停止这些定时器,你可以调用:clearInterval(intervalID);

参数:

  • callbackFunction:要每隔 intervalInMilliseconds 执行的函数。
  • intervalInMilliseconds:计时器在执行指定函数之间应延迟的时间,以毫秒(千分之一秒)为单位。1000 毫秒等于 1 秒。
  • arg1, arg2, ...:可选的额外参数,传递给 callbackFunction。

setInterval() 返回一个数字型的间隔 ID (interval ID),可以使用 clearInterval() 来停止该间隔定时器。

关键在于将实际的函数(函数引用、匿名函数或箭头函数)作为第一个参数传递。传递字符串形式的代码(例如,setInterval("myFunction()", 1000))是一种过时且不安全的做法,它内部使用了 eval(),强烈不推荐。

一个实际的用例是更新动态内容,比如时钟:

// 假设你有一个 HTML 元素,例如:<p id="clock"></p>
function displayTime() {
const now = new Date();
const timeString = now.toLocaleTimeString();
const clockElement = document.getElementById("clock");
if (clockElement) {
clockElement.textContent = timeString;
}
}
// 立即调用 displayTime 一次,以便在没有延迟的情况下显示时间
// displayTime();
// 然后每秒更新一次。运行此代码前,确保 HTML 元素存在。
// const clockInterval = setInterval(displayTime, 1000);
// 要停止时钟(例如,如果用户离开页面或点击了某个按钮):
// clearInterval(clockInterval);

在实际应用中,你通常会将 displayTime 调用和 setInterval 放在一个脚本中,该脚本在浏览器加载了 id='clock' HTML 元素后运行,或者使用像 DOMContentLoaded 这样的事件监听器。

要停止由 setInterval() 设置的间隔定时器,可以使用 clearInterval() 方法。它接受 setInterval() 返回的间隔 ID 作为参数。

clearInterval(intervalID);

要使用 clearInterval(),你必须将 setInterval() 返回的 ID 存储在一个变量中。这个变量不一定需要是全局的,但它必须在调用 clearInterval() 的作用域 (scope) 中可访问。

// 此示例所需的 HTML:
// <p id="timerDisplay">Loading...</p>
// <button id="stopButton">Stop Timer</button>
/*
const timerDisplayElement = document.getElementById("timerDisplay");
const stopButtonElement = document.getElementById("stopButton");
let timerIntervalID;
function updateTimerDisplay() {
const now = new Date();
if (timerDisplayElement) {
timerDisplayElement.textContent = now.toLocaleTimeString();
}
}
if (timerDisplayElement) {
updateTimerDisplay();
timerIntervalID = setInterval(updateTimerDisplay, 1000);
}
if (stopButtonElement) {
stopButtonElement.addEventListener('click', function() {
clearInterval(timerIntervalID);
if (timerDisplayElement) {
timerDisplayElement.textContent = "定时器已停止。";
}
console.log("定时器已通过按钮停止。");
});
}
*/

上面注释掉的代码演示了如何设置一个间隔定时器,然后使用按钮清除它。使用 addEventListener 是处理事件的现代方式。

setTimeout() 方法在指定的延迟后执行一个函数或代码片段一次。

// 首选语法:传递函数引用
let timeoutID = setTimeout(myDelayedFunction, 3000);
// 匿名函数示例:
let timeoutID_anon = setTimeout(function() {
console.log("Executed after 3 seconds");
}, 3000);
// 箭头函数示例:
let timeoutID_arrow = setTimeout(() => {
console.log("Arrow function executed after 3 seconds");
}, 3000);
// 传递参数:
function showMessage(message, type) {
console.log(`[${type.toUpperCase()}]: ${message}`);
}
let messageTimeout = setTimeout(showMessage, 2000, "Operation complete", "info");
// 在执行前取消这些定时器:clearTimeout(timeoutID);

参数:

  • callbackFunction:在 delayInMilliseconds 后要执行的函数。
  • delayInMilliseconds:等待的时间,以毫秒为单位,之后执行函数。
  • arg1, arg2, ...:可选的额外参数,传递给 callbackFunction。

setTimeout() 返回一个数字型的定时器 ID (timeout ID),可以使用 clearTimeout() 在它执行前取消该定时器。

与 setInterval() 一样,始终将实际的函数作为第一个参数传递,而不是字符串形式的代码。

// 所需 HTML:<button id="myButton">Greet after 3s</button>
/*
const myButton = document.getElementById('myButton');
if (myButton) {
myButton.addEventListener('click', function() {
console.log("Button clicked. Greeting will appear in 3 seconds...");
setTimeout(function() {
console.log("Hello there!");
// 或者:如果需要弹窗,可以使用 alert("Hello there!");
}, 3000);
});
}
*/

如果你想阻止一个计划执行的函数(例如,如果用户执行了另一个操作,使得定时器变得不必要),你可以使用 clearTimeout()。它接受 setTimeout() 返回的定时器 ID 作为参数。

clearTimeout(timeoutID);

要使用 clearTimeout(),你必须将 setTimeout() 返回的 ID 存储在一个在调用 clearTimeout() 的作用域中可访问的变量里。

如果在计时器到期之前调用 clearTimeout(),则计划的函数将不会执行。

// 所需 HTML:
// <button id="startButton">Start 3s Timeout</button>
// <button id="cancelButton">Cancel Timeout</button>
// <p id="statusMessage"></p>
/*
const startBtn = document.getElementById('startButton');
const cancelBtn = document.getElementById('cancelButton');
const statusMsg = document.getElementById('statusMessage');
let scheduledAlertID;
if (startBtn && cancelBtn && statusMsg) {
startBtn.addEventListener('click', function() {
statusMsg.textContent = "Timeout scheduled. Alert in 3 seconds.";
if (scheduledAlertID) {
clearTimeout(scheduledAlertID);
}
scheduledAlertID = setTimeout(function() {
alert('Hello from timeout!');
statusMsg.textContent = "Alert displayed!";
scheduledAlertID = null; // 执行后清除 ID
}, 3000);
});
cancelBtn.addEventListener('click', function() {
if (scheduledAlertID) {
clearTimeout(scheduledAlertID);
statusMsg.textContent = "Timeout cancelled.";
console.log("Timeout cancelled.");
scheduledAlertID = null;
} else {
statusMsg.textContent = "No active timeout to cancel.";
}
});
}
*/

setTimeout 和 clearTimeout 常用于实现“防抖”(debouncing)。这是一种限制函数调用频率的技术,确保它只在一段时间不活动后才运行。例如,如果你有一个搜索输入框,在用户输入时进行 API 调用,你可能希望等待用户暂停输入后再发送请求。

// HTML: <input type="search" id="searchInput" placeholder="Search..." />
/*
let debounceTimer;
function handleSearchInput(event) {
clearTimeout(debounceTimer);
const query = event.target.value;
debounceTimer = setTimeout(() => {
if (query.length > 0) { // 只在查询不为空时搜索
console.log(`Searching for: ${query}`);
// fetchSearchResults(query); // 实际的 API 调用会放在这里
} else {
console.log("Search query cleared.");
}
}, 500); // 等待 500ms 的不活动时间
}
const searchInput = document.getElementById('searchInput');
if (searchInput) {
searchInput.addEventListener('input', handleSearchInput);
}
*/

如前面时钟示例所示,setInterval 非常适合创建需要定期更新的功能,例如实时时钟、计数器或动画。