Alat-alat modern bekerja dengan cara reaktif: dev server memuat ulang kode begitu kita menyimpan berkas, formatter merapikan berkas otomatis, dan pipeline build berjalan saat aset berubah. Semuanya berdiri di atas satu kemampuan yang sama — mendengarkan perubahan berkas tanpa harus memeriksa terus-menerus. Node.js menyediakan watch dan watchFile untuk kebutuhan itu. Pada chapter ini kita mencoba keduanya, memahami jenis kejadian yang dilaporkan, dan mengenal batas-batasnya lintas platform.

Memantau Satu Berkas dengan fs/promises #

Versi promise dari watch mengembalikan async iterator: sumber kejadian yang bisa kita await satu per satu. Pola ini membuat urutan logika terbaca seperti resep — mulai pantau, tunggu kejadian, tutup pemantau — tanpa callback yang bersarang.

js
import { watch, writeFile, rm } from "node:fs/promises";

// Siapkan berkas yang akan dipantau
await rm("catatan-pantau.txt", { force: true });
await writeFile("catatan-pantau.txt", "isi versi 1\n");

// Mulai memantau; fs/promises.watch mengembalikan async iterator
const pemantau = watch("catatan-pantau.txt");
const janjiKejadian = pemantau.next();

// Perubahan ini memicu kejadian pada pemantau
await writeFile("catatan-pantau.txt", "isi versi 2\n");

const { value: kejadian } = await janjiKejadian;
console.log(`kejadian : ${kejadian.eventType}`);
console.log(`berkas   : ${kejadian.filename}`);

// Tutup pemantau agar program bisa keluar dengan rapi
await pemantau.return();
await rm("catatan-pantau.txt", { force: true });
console.log("pemantau ditutup, berkas uji dihapus");

Output yang Dihasilkan:

text
kejadian : change
berkas   : catatan-pantau.txt
pemantau ditutup, berkas uji dihapus

Mari kita telaah baris-baris kode di atas:

  1. Baris 4-5 (persiapan): berkas dipastikan mulai dari kondisi bersih memakai rm ber-force, lalu ditulis dengan isi versi 1. Pemantauan dimulai setelah berkas ada, karena watch pada berkas yang muncul belakangan butuh penanganan ekstra.
  2. Baris 8-9 (mulai memantau): watch("catatan-pantau.txt") membuka pemantau dan mengembalikan async iterator. Pemanggilan pemantau.next() mengembalikan promise yang akan selesai pada kejadian berikutnya — promise ini disimpan dulu sebagai janjiKejadian sebelum perubahan dipicu.
  3. Baris 12 (memicu perubahan): penulisan ulang berkas inilah yang memicu laporan dari sistem operasi.
  4. Baris 14-16 (menerima kejadian): await janjiKejadian mengembalikan hasil next(), dan properti value berisi kejadian: eventType berupa "change" untuk perubahan isi, sementara filename memuat nama berkas.
  5. Baris 19 (pemantau.return()): async iterator ditutup agar tidak ada proses yang menggantung; tanpa ini, program akan terus berjalan menunggu kejadian berikutnya yang tidak pernah datang.

Memantau Isi Direktori #

Memantau satu berkas jarang cukup — kebanyakan fitur ingin tahu apa pun yang terjadi dalam satu folder. watch pada direktori melaporkan kejadian untuk seluruh isinya, dengan nama berkas terkait pada properti filename.

js
import { watch, writeFile, rm, mkdir } from "node:fs/promises";

// Siapkan folder kosong yang dipantau isinya
await rm("folder-pantau", { recursive: true, force: true });
await mkdir("folder-pantau");

const pemantau = watch("folder-pantau");
const janjiPertama = pemantau.next();
const janjiKedua = pemantau.next();

// Berkas baru muncul: dilaporkan sebagai kejadian "rename"
await writeFile("folder-pantau/baru.txt", "isi pertama\n");
// Isi berkas berubah: dilaporkan sebagai kejadian "change"
await writeFile("folder-pantau/baru.txt", "isi kedua\n");

const pertama = await janjiPertama;
const kedua = await janjiKedua;
console.log(`kejadian 1: ${pertama.value.eventType} ${pertama.value.filename}`);
console.log(`kejadian 2: ${kedua.value.eventType} ${kedua.value.filename}`);

await pemantau.return();
await rm("folder-pantau", { recursive: true, force: true });
console.log("pemantau ditutup, folder uji dihapus");

Output yang Dihasilkan:

text
kejadian 1: rename baru.txt
kejadian 2: change baru.txt
pemantau ditutup, folder uji dihapus

Dua kejadian pada output membawa jenis berbeda. Munculnya baru.txt dilaporkan sebagai "rename" — bukan "create" — karena rename mencakup seluruh perubahan keanggotaan folder: berkas muncul, hilang, atau dipindahkan ke luar. Perubahan isi berkas dilaporkan sebagai "change". Baris 8-9 memanggil next() dua kali di muka; kedua promise menampung dua kejadian berikutnya secara berurutan, sehingga urutan laporan tetap tertata meski keduanya terjadi berdekatan.

watchFile: Alternatif Berbasis Polling #

Selain watch, ada watchFile yang bekerja dengan cara berbeda: memeriksa metadata berkas secara berkala dan membandingkan waktu modifikasinya. Bentuknya berbasis callback pada node:fs:

js Pola dasar fs.watchFile
import { watchFile, unwatchFile } from "node:fs";

watchFile("catatan.txt", { interval: 1000 }, (curr, prev) => {
  console.log(`ukuran sekarang: ${curr.size}, sebelumnya: ${prev.size}`);
  unwatchFile("catatan.txt");
});

Callback menerima dua object Stats — kondisi sekarang (curr) dan kondisi sebelumnya (prev) — sehingga kita bisa membandingkan apa yang berubah. Karena hanya mengandalkan pemeriksaan berkala, watchFile bekerja pada sistem berkas yang tidak mendukung mekanisme notifikasi (misalnya sebagian koneksi jaringan), tetapi boros pembandingan dan lambat merespons dibanding watch. Setelah selesai, unwatchFile menghentikan pemeriksaan; tanpa itu, interval terus berjalan selama proses hidup.

Perbandingan dan Batasan Lintas Platform #

AspekwatchwatchFile
MekanismeNotifikasi event dari sistem operasiPemeriksaan berkala (polling)
Kecepatan reaksiCepatTergantung interval
Beban sumber dayaRinganBertambah seiring banyaknya berkas
Dukungan sistem berkasTidak semua (mis. sebagian koneksi jaringan)Hampir semua
Bentuk APIEvent / async iteratorCallback dengan curr dan prev

Rujukan resmi: fs.watch , fsPromises.watch , dan fs.watchFile .

Pemantau bekerja baik selama semuanya berjalan mulus — tetapi berkas hilang, folder terkunci, dan izin ditolak adalah kenyataan sehari-hari operasi berkas. Chapter penutup section ini, Penanganan Error pada Filesystem, membaca kode error seperti ENOENT dan menyusun pola penanganan yang rapi.