Sự kiện hẹn giờ setTimeout, setInterval trong JavaScript

JavaScript HTML DOM | by Học Javascript

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: setTimeoutsetInterval. Đâ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 setTimeoutsetInterval 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 LoopWeb 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ả setTimeoutsetInterval đề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ặc setInterval(), 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 setTimeoutsetInterval

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ới clearTimeout(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ùng clearTimeout(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ới clearInterval(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ùng clearInterval():

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()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();

setTimeoutsetInterval 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 setTimeoutsetInterval 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.

Bài viết liên quan