Episode ini membedah mekanisme asynchronous JavaScript: state Promise, rantai .then dan .catch, sintaks async/await, serta Promise.all untuk eksekusi paralel. Kalian belajar menangani error asynchronous dengan benar dan menghindari callback yang berantakan.

Kode yang menunggu — fetch, setTimeout, baca file — sudah muncul di beberapa episode, tapi belum pernah dibedah. Episode 16 menjawab pertanyaan yang selalu tertunda: bagaimana JavaScript menangani pekerjaan yang hasilnya baru tersedia nanti? Jawabannya adalah Promise, dengan async/await sebagai cara modern menulisnya.
Promise muncul untuk memecahkan masalah callback hell: kode yang bersarang terlalu dalam karena setiap langkah menunggu langkah sebelumnya. Promise meratakan rantai itu, dan async/await membuatnya terbaca seperti kode synchronous biasa.
Episode ini adalah fondasi untuk semua aplikasi nyata — membaca API, menulis file, berkomunikasi dengan database. Kuasai state Promise, rantai .then dan .catch, async/await, lalu Promise.all untuk eksekusi paralel.
Promise adalah objek yang merepresentasikan hasil operasi asynchronous yang belum selesai. Dia punya tiga state:
const janji = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Berhasil diproses");
}, 1000);
});
janji.then((hasil) => {
console.log(hasil);
});new Promise((resolve, reject) => menerima fungsi executor. resolve menandai keberhasilan dan reject menandai kegagalan. Di sini resolve("Berhasil diproses") dipanggil setelah satu detik, dan janji.then(...) menerima nilainya. Sebuah Promise hanya berpindah state satu kali — dari pending ke fulfilled atau rejected.
Jika operasi gagal, panggil reject. Perhatikan: error di dalam Promise tidak terlihat oleh try...catch biasa di luar — karena Promise berjalan asynchronous:
const cek = new Promise((resolve, reject) => {
const sukses = false;
setTimeout(() => {
if (sukses) {
resolve("OK");
} else {
reject(new Error("Terjadi kegagalan"));
}
}, 500);
});
cek.catch((error) => {
console.error("Ditangkap:", error.message);
});reject(new Error("Terjadi kegagalan")) mengalihkan Promise ke state rejected. cek.catch(...) menangkapnya. Error async hanya bisa ditangkap lewat .catch, bukan try...catch synchronous yang ditempatkan di luar Promise.
.then bisa dirantai: setiap .then menerima nilai dari .then sebelumnya dan mengembalikan nilai baru — termasuk Promise lain yang akan ditunggu:
function dapatkanPengguna() {
return new Promise((resolve) => {
setTimeout(() => resolve({ id: 1, nama: "Arman" }), 300);
});
}
function dapatkanPosting(user) {
return new Promise((resolve) => {
setTimeout(() => resolve([`Posting dari ${user.nama}`]), 300);
});
}
dapatkanPengguna()
.then((user) => dapatkanPosting(user))
.then((posting) => console.log(posting))
.catch((error) => console.error(error));.then((user) => dapatkanPosting(user)) mengembalikan Promise baru yang ditunggu oleh .then berikutnya — inilah cara menyusun langkah berurutan tanpa nesting. .catch di akhir menangkap error dari semua langkah sebelumnya. Satu .catch di ujung rantai jauh lebih bersih daripada banyak handler per langkah.
async menandai fungsi yang selalu mengembalikan Promise, dan await menjeda eksekusi hingga Promise selesai:
async function prosesLengkap() {
const user = await dapatkanPengguna();
const posting = await dapatkanPosting(user);
return posting;
}
const hasil = await prosesLengkap();
console.log(hasil);await dapatkanPengguna() menjeda prosesLengkap sampai Promise selesai, lalu meneruskan nilainya. Hasilnya sama dengan rantai .then, tapi terbaca seperti kode synchronous dari atas ke bawah — sedangkan rantai .then semakin bersarang seiring bertambahnya langkah. await hanya legal di dalam fungsi async.
await berurutan membuang waktu ketika beberapa Promise tidak saling bergantung. Promise.all menjalankan semuanya secara paralel dan menunggu semuanya selesai:
async function muatDataParalel() {
const [pengguna, posting, komentar] = await Promise.all([
fetch("https://jsonplaceholder.typicode.com/users/1").then((r) => r.json()),
fetch("https://jsonplaceholder.typicode.com/posts/1").then((r) => r.json()),
fetch("https://jsonplaceholder.typicode.com/comments/1").then((r) => r.json()),
]);
return { pengguna, posting, komentar };
}
const data = await muatDataParalel();
console.log(data.pengguna.name);Promise.all([...]) menerima array Promise dan mengembalikan satu Promise yang selesai dengan array hasil dalam urutan yang sama. Ketiga fetch berjalan bersamaan, bukan berurutan. Jika salah satu gagal, Promise.all langsung rejected — hasil lain tidak dikembalikan.
Untuk async/await, error ditangkap dengan try...catch biasa:
async function aman() {
try {
const respons = await fetch("https://jsonplaceholder.typicode.com/posts/1");
if (!respons.ok) {
throw new Error(`HTTP ${respons.status}`);
}
return await respons.json();
} catch (error) {
console.error("Gagal memuat data:", error.message);
return { title: "Fallback" };
}
}
console.log(await aman());try membungkus operasi yang bisa gagal; catch (error) menangkap error dari await, termasuk yang dilempar oleh throw di dalam try. Mengembalikan nilai fallback di catch membuat fungsi tetap menghasilkan data yang bisa dipakai antarmuka — pola yang umum di production.
Tip
Pilih dengan niat: gunakan await berurutan untuk langkah yang saling bergantung, Promise.all untuk operasi independen yang ingin dijalankan paralel, dan Promise.allSettled jika kalian ingin tahu hasil setiap Promise meskipun ada yang gagal. Tiga pilihan ini mencakup hampir semua kebutuhan asynchronous.
Episode 16 menuntaskan pemahaman asynchronous: state Promise yang berpindah dari pending ke fulfilled atau rejected, rantai .then dan .catch yang meratakan callback bersarang, sintaks async/await yang membuat kode terbaca berurutan, serta Promise.all untuk eksekusi paralel dengan try...catch yang bersih.
Inti yang harus dibawa pulang:
.catch menangkap error async; try...catch biasa tidak bisa menjangkau Promise.async selalu mengembalikan Promise; await menjeda hingga selesai.async/await lebih terbaca daripada rantai .then untuk langkah berurutan.Promise.all menjalankan Promise independen secara paralel.async/await dengan try...catch dan beri fallback.Di episode 17 selanjutnya kita akan membahas form validation dan interaksi pengguna — memvalidasi input dengan HTML5 dan JavaScript custom, menampilkan pesan error yang jelas, serta memproses submit form secara asynchronous. Kalian membangun form yang andal dan ramah pengguna.