Async JavaScript Tuntas: Callback, Promise, sampai Async/Await

Evolusi cara JavaScript menangani operasi asinkron — dari callback hell sampai async/await yang bersih. Panduan komprehensif dengan gotcha yang perlu dihindari.
Async JavaScript Tuntas: Callback, Promise, sampai Async/Await

Kenapa JavaScript Perlu Mekanisme Async?

JavaScript adalah single-threaded — hanya ada satu call stack. Jika operasi yang lambat (network request, file I/O) berjalan synchronous, seluruh program akan freeze menunggu selesai. Mekanisme async memungkinkan JavaScript "melanjutkan hidup" sambil menunggu operasi lambat selesai.

Era 1: Callback

fs.readFile("data.json", "utf8", (err, data) => {
  if (err) return handleError(err);
  parseJSON(data, (err, parsed) => {
    if (err) return handleError(err);
    saveToDb(parsed, (err, result) => {
      // Callback hell dimulai...
    });
  });
});

Masalah utama: callback hell (pyramid of doom), error handling yang repetitif, dan composability yang buruk.

Era 2: Promise

fs.promises.readFile("data.json", "utf8")
  .then(data => parseJSON(data))
  .then(parsed => saveToDb(parsed))
  .then(result => console.log("Done:", result))
  .catch(err => handleError(err))  // satu handler untuk semua error
  .finally(() => cleanup());

Lebih bersih, tapi chaining panjang masih bisa membingungkan, dan error handling di dalam .then() tetap tricky.

Era 3: Async/Await

async function processData() {
  try {
    const raw    = await fs.promises.readFile("data.json", "utf8");
    const parsed = await parseJSON(raw);
    const result = await saveToDb(parsed);
    console.log("Done:", result);
  } catch (err) {
    handleError(err);
  } finally {
    cleanup();
  }
}

Kode async yang dibaca seperti synchronous. Ini yang paling direkomendasikan untuk kode baru.

Gotcha yang Sering Bikin Bug

Await dalam Loop

// ❌ Sequential — lambat
for (const id of userIds) {
  const user = await fetchUser(id); // tunggu satu per satu
}

// ✅ Parallel — jauh lebih cepat
const users = await Promise.all(userIds.map(id => fetchUser(id)));

Error dari Promise.all

// ❌ Satu gagal, semuanya gagal
const [a, b] = await Promise.all([fetchA(), fetchB()]);

// ✅ Handle kegagalan per-item
const results = await Promise.allSettled([fetchA(), fetchB()]);
results.forEach(r => {
  if (r.status === "fulfilled") console.log(r.value);
  else console.error(r.reason);
});

Async Tanpa Await

// ❌ Error tidak tertangkap — floating promise
someAsyncFunction(); // tidak ada await, error hilang

// ✅
await someAsyncFunction();
// atau jika sengaja fire-and-forget:
someAsyncFunction().catch(err => console.error(err));

Tip: AbortController untuk Cancelable Request

const controller = new AbortController();
setTimeout(() => controller.abort(), 5000); // timeout 5 detik

try {
  const res = await fetch("/api/data", { signal: controller.signal });
} catch (err) {
  if (err.name === "AbortError") console.log("Request dibatalkan");
}

Butuh Solusi Digital Custom?

Kami siap membuatkan solusi digital sesuai kebutuhan bisnis Anda.

Konsultasi Gratis