Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> JavaScript

Dừng hàm đang thực thi trong JavaScript (clearInterval/clearTimeout)

Để dừng một hàm đang chạy lặp lại (interval) hoặc chạy sau delay (timeout), lưu ID trả về từ setInterval/setTimeout và dùng clearInterval/clearTimeout.

Cơ chế:

// BẮT ĐẦU
const timerId = setInterval(callback, delayMs); // Lặp lại
const timeoutId = setTimeout(callback, delayMs); // Chạy 1 lần sau delay

// DỪNG
clearInterval(timerId); // Dừng interval
clearTimeout(timeoutId); // Hủy timeout chưa chạy

Ví dụ minh họa

<!DOCTYPE html>
<html lang="vi">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Dừng hàm JS</title>
  <style>
    body { font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; padding: 20px; }
    button { padding: 10px 20px; margin: 5px; cursor: pointer; font-size: 16px; }
    #log { font-family: monospace; background: #f5f5f5; padding: 10px; height: 200px; overflow: auto; border: 1px solid #ddd; }
    .running { background: #e8f5e9; }
    .stopped { background: #ffebee; }
  </style>
</head>
<body>
  <h1>Dừng hàm đang thực thi với clearInterval</h1>
  <button id="startBtn">BẮT ĐẦU (setInterval)</button>
  <button id="stopBtn" disabled>DỪNG (clearInterval)</button>
  <button id="clearBtn">XÓA LOG</button>
  <div id="log"></div>
  
  <script>
    const startBtn = document.getElementById('startBtn');
    const stopBtn = document.getElementById('stopBtn');
    const clearBtn = document.getElementById('clearBtn');
    const log = document.getElementById('log');
    
    let intervalId = null;
    let counter = 0;
    
    function logMessage(msg, type = '') {
      const div = document.createElement('div');
      div.textContent = `[${new Date().toLocaleTimeString()}] ${msg}`;
      if (type) div.className = type;
      log.prepend(div);
    }
    
    startBtn.addEventListener('click', () => {
      if (intervalId) return; // Đang chạy
      counter = 0;
      intervalId = setInterval(() => {
        counter++;
        logMessage(`Interval chạy lần ${counter}`, 'running');
      }, 1000);
      startBtn.disabled = true;
      stopBtn.disabled = false;
    });
    
    stopBtn.addEventListener('click', () => {
      if (intervalId) {
        clearInterval(intervalId);
        intervalId = null;
        logMessage('⏹ Interval đã DỪNG', 'stopped');
        startBtn.disabled = false;
        stopBtn.disabled = true;
      }
    });
    
    clearBtn.addEventListener('click', () => log.innerHTML = '');
  </script>
</body>
</html>

Kết quả

Nhấn BẮT ĐẦU → Log in "Interval chạy lần 1, 2, 3..." mỗi giây.

Nhấn DỪNG → Log "⏹ Interval đã DỪNG", interval dừng hẳn.

Các trường hợp sử dụng phổ biến:

Tình huốngAPIDừng bằng
Lặp lại định kỳ (polling, animation, clock)setIntervalclearInterval(id)
Chạy 1 lần sau delay (debounce, timeout)setTimeoutclearTimeout(id)
Animation frame (60fps)requestAnimationFramecancelAnimationFrame(id)
Idle callbackrequestIdleCallbackcancelIdleCallback(id)

Pattern phổ biến: Debounce (trì hoãn thực thi)

function debounce(fn, delay) {
  let timeoutId;
  return (...args) => {
    clearTimeout(timeoutId); // Hủy lần trước
    timeoutId = setTimeout(() => fn(...args), delay);
  };
}

// Usage: chỉ search khi user ngừng gõ 300ms
const search = debounce((query) => api.search(query), 300);
input.addEventListener('input', e => search(e.target.value));

Pattern: Throttle (giới hạn tần suất)

function throttle(fn, limit) {
  let inThrottle;
  return (...args) => {
    if (!inThrottle) {
      fn(...args);
      inThrottle = true;
      setTimeout(() => inThrottle = false, limit);
    }
  };
}

// Usage: scroll handler tối đa 1 lần/100ms
window.addEventListener('scroll', throttle(() => console.log('scroll'), 100));

⚠️ Lưu ý quan trọng:

  • Luôn lưu ID trả về để clear sau này
  • clearInterval/clearTimeout an toàn nếu ID null/undefined (không throw)
  • Trong React: dùng useEffect cleanup: return () => clearInterval(id)
  • Memory leak: quên clear interval khi component unmount