Sự kiện hẹn giờ setTimeout, setInterval trong JavaScript
JavaScript HTML DOM | by
Trong quá trình phát triển ứng dụng web, việc kiểm soát thời gian và thực thi các tác vụ theo lịch trình là một nhu cầu rất phổ biến. JavaScript cung cấp cho lập trình viên hai công cụ mạnh mẽ để xử lý các sự kiện liên quan đến thời gian: setTimeout
và setInterval
. Đây là những hàm hẹn giờ giúp trì hoãn hoặc lặp lại việc thực thi một đoạn mã theo khoảng thời gian xác định. Dù đơn giản về cú pháp, nhưng khi được sử dụng đúng cách, chúng có thể tạo ra trải nghiệm người dùng mượt mà hơn, linh hoạt hơn — từ việc hiển thị thông báo, cập nhật thời gian thực, đến xây dựng các hiệu ứng động.
Trong bài viết này, mình sẽ cùng tìm hiểu chi tiết cách hoạt động, ứng dụng thực tế và những lưu ý quan trọng khi sử dụng setTimeout
và setInterval
trong JavaScript.
Khái niệm về sự kiện hẹn giờ trong JavaScript
JavaScript đơn luồng và mô hình xử lý bất đồng bộ
JavaScript là một ngôn ngữ đơn luồng, tức là tại một thời điểm chỉ thực thi một tác vụ duy nhất. Điều này giúp tránh xung đột dữ liệu nhưng lại dễ dẫn đến tình trạng "đóng băng" nếu một tác vụ nào đó mất quá nhiều thời gian để xử lý.
Để giải quyết vấn đề này, JavaScript áp dụng mô hình xử lý bất đồng bộ (asynchronous) với sự hỗ trợ của Event Loop và Web APIs như setTimeout
, setInterval
, fetch
, v.v. Các hàm hẹn giờ không chặn luồng chính mà được đưa vào hàng đợi thực thi sau khi thời gian chờ kết thúc.
Cơ chế hoạt động của bộ hẹn giờ (Timer API)
Cả setTimeout
và setInterval
đều là Web API được trình duyệt cung cấp. Cơ chế hoạt động của chúng như sau:
-
Khi gọi
setTimeout()
hoặcsetInterval()
, trình duyệt ghi nhận hàm callback và thiết lập một đồng hồ đếm ngược. -
Sau khi thời gian quy định trôi qua, hàm callback không thực thi ngay lập tức mà được đưa vào hàng đợi tác vụ (callback queue).
-
Event Loop kiểm tra nếu luồng chính (call stack) rỗng thì mới lấy callback ra để thực thi.
Do đó, thời gian thực tế để thực thi một hàm có thể chậm hơn thời gian lập lịch nếu luồng chính đang bận xử lý một tác vụ khác.
So sánh tổng quan giữa setTimeout
và setInterval
Tiêu chí | setTimeout() |
setInterval() |
---|---|---|
Mục đích | Thực thi một hàm sau một khoảng thời gian nhất định (chỉ 1 lần). | Thực thi một hàm lặp đi lặp lại sau khoảng thời gian đều đặn. |
Trả về | Một ID để có thể huỷ bằng clearTimeout() |
Một ID để huỷ bằng clearInterval() |
Dừng lặp | Không cần – chỉ chạy một lần | Cần gọi clearInterval() để dừng lặp |
Ứng dụng phổ biến | Delay hành động, tạo hiệu ứng tạm dừng | Đồng hồ đếm ngược, cập nhật thời gian thực, slide show tự động |
Sự hiểu rõ về cơ chế hoạt động và sự khác biệt của hai hàm này là tiền đề quan trọng để sử dụng hiệu quả trong phát triển ứng dụng web hiện đại.
setTimeout trong JavaScript
Cú pháp
setTimeout(function, delay, param1, param2, ...);
function: Hàm (hoặc đoạn mã) sẽ được thực thi sau thời gian delay.
delay: Thời gian chờ (tính bằng mili giây), sau đó hàm mới được gọi.
param1, param2, ... (tùy chọn): Các tham số truyền vào hàm nếu cần.
Lưu ý:
setTimeout()
trả về một ID, có thể dùng vớiclearTimeout(id)
để hủy hẹn giờ nếu cần.
Mô tả
-
setTimeout
là một hàm hẹn giờ chạy một lần duy nhất. -
Sau khi thời gian delay trôi qua, hàm callback được đưa vào hàng đợi (callback queue), và sẽ được thực thi khi luồng chính rảnh.
-
Dùng trong các tình huống cần trì hoãn hành động.
Ví dụ thực tế
Ví dụ 1: Hiển thị thông báo sau 3 giây
setTimeout(() => { alert("Chào bạn! Đây là thông báo sau 3 giây."); }, 3000);
Ví dụ 2: Ẩn một phần tử HTML sau 5 giây
<div id="quangcao">Quảng cáo sẽ biến mất sau 5 giây...</div> <script> setTimeout(() => { document.getElementById("quangcao").style.display = "none"; }, 5000); </script>
Ví dụ 3: Truyền tham số vào hàm callback
function xinChao(ten) { alert("Xin chào, " + ten + "!"); } setTimeout(xinChao, 2000, "Trung Kiên");
Lưu ý nhỏ
-
Nếu
delay = 0
, hàm vẫn không chạy ngay lập tức. Nó được đưa vào hàng đợi và chỉ thực thi sau khi call stack rỗng. -
Để hủy một
setTimeout
, dùngclearTimeout(timeoutId)
:
const timeoutId = setTimeout(() => { console.log("Không bao giờ chạy"); }, 5000); clearTimeout(timeoutId);
setInterval trong JavaScript
Cú pháp
setInterval(function, interval, param1, param2, ...);
function: Hàm (hoặc đoạn mã) cần thực thi lặp lại.
interval: Khoảng thời gian giữa mỗi lần gọi hàm (tính bằng mili giây).
param1, param2, ... (tùy chọn): Các tham số truyền vào hàm callback nếu cần.
Giống
setTimeout
, hàm này trả về một ID. Bạn có thể dùng ID đó vớiclearInterval(id)
để dừng vòng lặp.
Mô tả
-
setInterval
thực thi hàm callback lặp đi lặp lại sau mỗi khoảng thời gian được chỉ định. -
Nó tiếp tục thực thi cho đến khi bị dừng bằng
clearInterval()
hoặc khi trang web được đóng/tải lại. -
Sử dụng trong các trường hợp cần hành động lặp lại định kỳ: cập nhật giao diện, đếm thời gian, tự động tải lại dữ liệu,...
Ví dụ thực tế
Ví dụ 1: Hiển thị đồng hồ thời gian thực
setInterval(() => { const now = new Date(); console.log(now.toLocaleTimeString()); }, 1000); // Mỗi giây in ra giờ hiện tại
Ví dụ 2: Tự động chuyển slide trong carousel ảnh
let currentSlide = 0; const slides = document.querySelectorAll(".slide"); function showSlide(index) { slides.forEach(slide => slide.style.display = "none"); slides[index].style.display = "block"; } setInterval(() => { currentSlide = (currentSlide + 1) % slides.length; showSlide(currentSlide); }, 3000); // Chuyển slide mỗi 3 giây
Ví dụ 3: Truyền tham số vào callback
function xinChao(ten) { console.log("Xin chào, " + ten); } setInterval(xinChao, 2000, "Đậu Trung Kiên"); // In "Xin chào, Đậu Trung Kiên" mỗi 2 giây
Lưu ý nhỏ
-
Nếu hàm callback chạy lâu hơn thời gian giữa các lần gọi, các lần lặp có thể bị chồng chéo, dẫn đến lỗi logic hoặc giảm hiệu suất.
-
Để dừng
setInterval
, dùngclearInterval()
:
const intervalId = setInterval(() => { console.log("Chạy mỗi 2 giây"); }, 2000); setTimeout(() => { clearInterval(intervalId); console.log("Đã dừng lặp"); }, 10000); // Dừng sau 10 giây
Dừng sự kiện hẹn giờ trong JavaScript
Khi sử dụng setTimeout
hoặc setInterval
, JavaScript sẽ trả về một ID đại diện cho timer đó. Bạn có thể sử dụng ID này để hủy hoặc dừng việc thực thi thông qua hai hàm clearTimeout()
và clearInterval()
.
clearTimeout(timeoutID)
-
Chức năng: Dừng một hành động được hẹn giờ thực hiện một lần bằng
setTimeout
. -
Sử dụng khi: Bạn muốn hủy bỏ hành động trước khi nó xảy ra (ví dụ người dùng đã tương tác nên không cần hiển thị thông báo nữa).
Ví dụ:
const timeoutId = setTimeout(() => { console.log("Thông báo sau 5 giây"); }, 5000); // Hủy nếu người dùng bấm nút document.getElementById("cancelBtn").addEventListener("click", () => { clearTimeout(timeoutId); console.log("Đã huỷ thông báo"); });
clearInterval(intervalID)
-
Chức năng: Dừng một hành động lặp lại theo chu kỳ được thiết lập bằng
setInterval
. -
Sử dụng khi: Bạn muốn ngắt vòng lặp khi đã đạt điều kiện nào đó (ví dụ: sau một khoảng thời gian, hoặc khi người dùng yêu cầu dừng).
Ví dụ:
let count = 0; const intervalId = setInterval(() => { console.log("Lặp lần: " + (++count)); }, 1000); // Dừng sau 10 giây setTimeout(() => { clearInterval(intervalId); console.log("Đã dừng lặp sau 10 giây"); }, 10000);
Ví dụ minh hoạ tổng hợp
Ví dụ 1: Dừng đồng hồ sau 10 giây
const clock = setInterval(() => { const now = new Date(); console.log(now.toLocaleTimeString()); }, 1000); setTimeout(() => { clearInterval(clock); console.log("Đã dừng đồng hồ sau 10 giây"); }, 10000);
Ví dụ 2: Huỷ thông báo nếu người dùng tương tác
const notice = setTimeout(() => { alert("Bạn vẫn đang ở đó chứ?"); }, 10000); // thông báo sau 10 giây // Nếu người dùng bấm bất kỳ phím nào → huỷ window.addEventListener("keydown", () => { clearTimeout(notice); console.log("Người dùng đã hoạt động - không cần thông báo"); });
Ứng dụng thực tế trong JavaScript
Bộ hẹn giờ trong JavaScript là công cụ cực kỳ hữu ích, đặc biệt trong các ứng dụng web có yếu tố tương tác hoặc thời gian thực. Dưới đây là những ứng dụng phổ biến:
Hẹn giờ thông báo người dùng khi không hoạt động
Giúp cải thiện trải nghiệm người dùng và bảo mật thông tin, đặc biệt với hệ thống đăng nhập:
let inactivityTimeout = setTimeout(() => { alert("Bạn đã không hoạt động trong 5 phút!"); }, 300000); // 5 phút document.addEventListener("mousemove", () => { clearTimeout(inactivityTimeout); inactivityTimeout = setTimeout(() => { alert("Bạn đã không hoạt động trong 5 phút!"); }, 300000); });
Tạo hiệu ứng chuyển động đơn giản
Ví dụ như di chuyển một phần tử sang phải mỗi 50ms:
let position = 0; const box = document.getElementById("box"); const move = setInterval(() => { if (position >= 300) { clearInterval(move); } else { position += 5; box.style.left = position + "px"; } }, 50);
Cập nhật dữ liệu định kỳ từ server (Polling)
Thay vì dùng WebSocket, bạn có thể dùng polling định kỳ:
setInterval(() => { fetch("/api/new-data") .then(response => response.json()) .then(data => { console.log("Dữ liệu mới:", data); }); }, 5000); // mỗi 5 giây
Chạy animation hoặc update giao diện theo thời gian
Ví dụ như đếm ngược hoặc cập nhật đồng hồ:
let countdown = 10; const display = document.getElementById("timer"); const timer = setInterval(() => { display.textContent = countdown; countdown--; if (countdown < 0) { clearInterval(timer); display.textContent = "Hết giờ!"; } }, 1000);
Lưu ý khi sử dụng trong JavaScript
Không nên dùng setInterval
nếu hàm callback quá nặng
Nếu thời gian thực thi hàm dài hơn khoảng lặp, các lần gọi có thể bị chồng chéo, gây lỗi logic hoặc làm chậm hệ thống. Trong trường hợp đó, nên dùng setTimeout
theo cách tự lặp:
function loop() { doHeavyTask(); setTimeout(loop, 1000); } loop();
setTimeout
và setInterval
không chính xác tuyệt đối
Do JavaScript chạy trên một luồng đơn (single-threaded), nếu luồng chính bị bận (do script nặng, rendering, hay user interaction), thời gian hẹn giờ có thể bị trễ:
setTimeout(() => { console.log("In ra sau 100ms (nhưng có thể trễ hơn)"); }, 100);
Nếu cần thời gian chính xác hơn, hãy cân nhắc dùng
performance.now()
hoặc Web Worker (trong ứng dụng phức tạp hơn).
Cần dọn dẹp timer khi không còn cần thiết
Đặc biệt trong các ứng dụng động như SPA, nếu không clear đúng cách, các setInterval
hay setTimeout
cũ có thể tiếp tục chạy → gây rò rỉ bộ nhớ và hành vi không mong muốn:
useEffect(() => { const id = setInterval(() => { // logic cập nhật }, 1000); return () => clearInterval(id); // cleanup khi component bị huỷ }, []);
Kết bài
Sự kiện hẹn giờ với setTimeout
và setInterval
là một phần không thể thiếu trong lập trình JavaScript, đặc biệt khi xử lý các tác vụ bất đồng bộ hoặc tạo hiệu ứng tương tác theo thời gian. Việc nắm vững cách sử dụng, hiểu rõ sự khác biệt và biết cách quản lý các bộ hẹn giờ sẽ giúp bạn xây dựng các ứng dụng web hiệu quả, mượt mà và thân thiện với người dùng. Tuy nhiên, hãy luôn lưu ý đến hiệu suất và sự an toàn trong quản lý tài nguyên để tránh các lỗi phổ biến như rò rỉ bộ nhớ hoặc chồng lặp logic. Khi sử dụng đúng cách, các hàm hẹn giờ sẽ trở thành công cụ mạnh mẽ trong tay bất kỳ lập trình viên front-end nào.