JavaScript adalah bahasa pemrograman yang berjalan pada lingkungan berutas tunggal (single-threaded). Artinya, mesin JavaScript hanya dapat melakukan satu pekerjaan dalam satu waktu pada utas utamanya. Bayangkan jika sebuah aplikasi harus mengunduh data gambar sebesar 5 megabyte dari server, dan browser membeku total menolak tombol klik pengguna hingga unduhan selesai!
Agar hal mengerikan tersebut tidak terjadi, JavaScript mengadopsi model non-pemblokir (non-blocking asynchronous model). Mari kita kupas tuntas bagaimana evolusi penanganan proses asinkron di JavaScript dari masa kelam hingga standar elegan masa kini.
1. Tragedi Masa Lalu: Callback Hell (Pyramid of Doom)
Pada awalnya, proses asinkron ditangani menggunakan fungsi callbackβsebuah fungsi yang dioperasikan sebagai argumen ke fungsi lain untuk dijalankan setelah tugas selesai. Masalah muncul saat tugas harus dieksekusi secara berurutan:
getUser(userId, function(user) {
getOrders(user.id, function(orders) {
getOrderDetails(orders[0].id, function(details) {
// Kode menjorok ke kanan tak terhingga dan sulit dibaca!
});
});
});
2. Fajar Baru: Objek Promise
Diperkenalkan pada standar ECMAScript 2015 (ES6), Promise merepresentasikan sebuah nilai yang mungkin tersedia sekarang, di masa depan, atau tidak pernah sama sekali. Promise memiliki 3 status:
- Pending: Tugas sedang berjalan di latar belakang.
- Fulfilled (Resolved): Tugas berhasil diselesaikan.
- Rejected: Tugas gagal akibat error jaringan atau validasi.
3. Standar Modern Paling Bersih: Async / Await
Sintaks async/await (hadir di ES2017) adalah pemanis sintaks (*syntactic sugar*) di atas Promises yang memungkinkan kita menulis kode asinkron dengan gaya sekuensial yang mudah dipahami manusia layaknya kode sinkron:
async function fetchStudentDashboard(studentId) {
try {
console.log("Memulai pengambilan data profil...");
const response = await fetch(`/api/students/${studentId}`);
if (!response.ok) {
throw new Error(`Gagal menghubungi server HTTP status: ${response.status}`);
}
const data = await response.json();
console.log("Data berhasil diterima:", data);
return data;
} catch (error) {
console.error("Terjadi kendala jaringan:", error.message);
// Tampilkan pesan error ramah pengguna di antarmuka
} finally {
console.log("Proses selesai, sembunyikan spinner loading.");
}
}
Kombinasi kata kunci async, await, dan blok penanganan try...catch membuat kode Anda aman dari unhandled rejection dan mudah diuji dengan unit testing.