Memilih Antara setTimeout, setInterval, dan requestAnimationFrame

Tiga fungsi timer di JavaScript punya karakter berbeda. Pahami kapan setTimeout, setInterval, dan requestAnimationFrame tepat dipakai agar kode tidak boros dan animasi tetap halus.

Meja kerja pengembang dengan laptop menampilkan kode JavaScript dan jam analog

Kamu membuat tombol notifikasi yang muncul tiga detik setelah halaman dimuat. Lalu ada jam digital yang berdetak tiap detik. Belakangan, kamu ingin elemen bergerak halus mengikuti scroll. Tiga situasi itu terlihat mirip, tetapi memakai alat yang sama akan membuat salah satunya terasa janggal. JavaScript menyediakan setTimeout, setInterval, dan requestAnimationFrame; masing-masing dirancang untuk kebutuhan yang berbeda.

Perbandingan ketiganya mencakup cara kerja, ketepatan waktu, dan dampaknya pada performa, supaya kamu bisa memilih tanpa menebak-nebak.

Cara kerja singkat masing-masing

setTimeout menjalankan satu fungsi setelah jeda tertentu. Fungsi itu dipanggil sekali, lalu selesai. Kamu bisa membatalkannya dengan clearTimeout jika keadaan berubah sebelum waktu habis.

setInterval memanggil fungsi berulang dengan jeda tetap antar panggilan. Selama tidak dihentikan lewat clearInterval, ia terus berjalan. Ini cocok untuk tugas periodik yang tidak menuntut presisi tinggi, seperti memperbarui teks jam atau mengecek status koneksi.

requestAnimationFrame meminta browser menjalankan fungsi sebelum frame berikutnya digambar. Browser mengatur ritmenya, biasanya mendekati 60 kali per detik pada layar standar. Fungsi yang kamu kirim menerima timestamp, sehingga kamu bisa menghitung progres animasi berdasarkan waktu, bukan jumlah panggilan.

Ketepatan waktu dan beban kerja

setTimeout dan setInterval tidak menjamin eksekusi tepat pada waktunya. Keduanya masuk ke antrean tugas dan baru dijalankan ketika thread utama kosong. Jika ada skrip berat yang sedang berjalan, timer bisa tertunda. Pada setInterval, penundaan ini bisa menumpuk: panggilan berikutnya tetap dijadwalkan, sehingga eksekusi bisa beruntun ketika thread kembali longgar.

requestAnimationFrame bekerja berbeda. Browser menyelaraskan pemanggilan dengan siklus render. Jika tab tidak aktif, pemanggilan dihentikan sementara, sehingga tidak ada pekerjaan sia-sia di latar belakang. Untuk animasi, ini menghasilkan gerakan yang lebih halus karena perubahan gaya terjadi tepat sebelum frame digambar.

Timer bukan penentu tunggal mulusnya animasi. Beban kerja di dalam callback tetap berpengaruh besar.

Kapan memakai setTimeout

Gunakan setTimeout untuk penundaan sekali jalan. Contohnya menampilkan toast yang hilang setelah beberapa detik, menunda pengiriman form setelah validasi, atau memberi jeda sebelum menjalankan pencarian saat pengguna berhenti mengetik (debounce).

  • Menunda eksekusi satu fungsi tanpa pengulangan.
  • Membatalkan rencana eksekusi ketika kondisi berubah, misalnya pengguna menutup modal sebelum timer selesai.
  • Mengatur urutan sederhana antar tugas yang tidak sensitif terhadap waktu.

Jika kamu perlu menangani kemungkinan error di dalam callback, bungkus dengan try-catch seperti yang dibahas di panduan try-catch JavaScript. Timer tidak menangkap error secara otomatis.

Kapan memakai setInterval

setInterval berguna untuk tugas berulang yang tidak memerlukan presisi tinggi dan tidak berat. Contohnya memperbarui jam digital, memeriksa kedaluwarsa sesi, atau memutar daftar pengumuman secara berkala.

Namun, hati-hati jika callback memakan waktu lebih lama dari interval yang ditentukan. Eksekusi bisa saling tumpang tindih atau tertunda tanpa kendali. Untuk tugas yang butuh jeda dinamis, setTimeout berantai lebih aman: jalankan setTimeout di akhir callback untuk menjadwalkan putaran berikutnya setelah pekerjaan selesai.

Selalu simpan ID interval dan panggil clearInterval saat komponen dilepas atau halaman ditinggalkan. Interval yang lupa dibersihkan akan terus berjalan dan membebani memori.

Kapan memakai requestAnimationFrame

Pilih requestAnimationFrame untuk semua yang terlihat bergerak: transisi posisi, perubahan opacity, animasi canvas, atau efek parallax. Browser akan menyesuaikan dengan refresh rate layar, sehingga animasi tetap mulus di perangkat dengan layar 120Hz sekaligus menghemat daya di layar 60Hz.

Di dalam callback, hitung kemajuan berdasarkan selisih waktu, bukan dengan menambah nilai tetap setiap frame. Pola sederhananya seperti ini:

let mulai;
function langkah(waktu) {
  if (!mulai) mulai = waktu;
  const progres = Math.min((waktu - mulai) / 1000, 1);
  elemen.style.transform = `translateX(${progres * 200}px)`;
  if (progres < 1) requestAnimationFrame(langkah);
}
requestAnimationFrame(langkah);

Untuk animasi yang dipicu interaksi, simpan ID dari requestAnimationFrame dan batalkan dengan cancelAnimationFrame ketika animasi baru dimulai. Ini mencegah dua loop berjalan bersamaan.

Perbandingan singkat

Aspek setTimeout setInterval requestAnimationFrame
Frekuensi Sekali Berulang Setiap frame
Ketepatan Tidak dijamin Tidak dijamin, bisa menumpuk Selaras dengan render
Perilaku di tab nonaktif Tetap berjalan, bisa tertunda Tetap berjalan, bisa tertunda Dihentikan sementara
Penggunaan utama Penundaan sekali Tugas periodik ringan Animasi dan visual

Untuk kebutuhan penyimpanan data yang berkala, misalnya menyimpan draf ke localStorage, pilihan antara localStorage dan sessionStorage lebih menentukan daripada jenis timernya. Kamu bisa melihat perbandingannya di artikel localStorage vs sessionStorage vs cookie.

Kesalahan yang sering terjadi

Memakai setInterval untuk animasi adalah sumber umum gerakan tersendat. Interval 16 milidetik tidak otomatis menghasilkan 60 frame per detik, karena browser tetap harus mengatur render dan pekerjaan lain. Sebaliknya, memakai requestAnimationFrame untuk tugas yang tidak berhubungan dengan tampilan hanya membuang siklus render.

Kesalahan lain adalah mengabaikan pembersihan. Timer yang tidak dibatalkan saat elemen dihapus dari DOM akan terus memegang referensi, sehingga memori tidak kembali. Simpan ID timer di variabel yang bisa diakses oleh fungsi pembersih.

Jika callback timer perlu menunggu operasi asynchronous seperti fetch, jangan campur setTimeout dengan await tanpa perencanaan. Gunakan pola async/await yang benar seperti di panduan async/await agar urutan eksekusi tetap jelas.

Ringkasan

setTimeout untuk penundaan sekali, setInterval untuk tugas berulang yang ringan dan tidak sensitif waktu, dan requestAnimationFrame untuk apa pun yang bergerak di layar. Ketiganya perlu dibersihkan saat tidak lagi dipakai. Mulailah dari kebutuhan: apakah fungsi harus berjalan sekali, berulang, atau mengikuti frame render.

Pertanyaan yang Sering Diajukan

Apakah requestAnimationFrame bisa menggantikan setInterval untuk animasi?

Ya, untuk animasi visual requestAnimationFrame lebih tepat karena diselaraskan dengan render dan berhenti saat tab tidak aktif. Namun, untuk tugas nonvisual seperti mengecek status server, setInterval atau setTimeout berantai lebih sesuai.

Mengapa animasi dengan setInterval terlihat patah-patah?

Karena interval tetap tidak memperhitungkan waktu render browser. Jika thread utama sibuk, panggilan tertunda dan posisi elemen melompat. requestAnimationFrame memberi timestamp sehingga kamu bisa menghitung posisi berdasarkan waktu nyata.

Bagaimana cara menghentikan timer yang sudah berjalan?

Simpan nilai kembalian dari pemanggilan. Gunakan clearTimeout untuk setTimeout, clearInterval untuk setInterval, dan cancelAnimationFrame untuk requestAnimationFrame. Panggil fungsi pembersih saat komponen dilepas atau kondisi berubah.