Rantai then sudah menyembunyikan sarang callback, tetapi masih menuntut kita berpikir dalam bentuk handler: setiap langkah ditulis sebagai function yang menerima hasil langkah sebelumnya. async dan await — tersedia sejak ES2017 — menyediakan sintaks yang tetap dibangun di atas promise, namun terbaca dari atas ke bawah seperti kode sinkron. Bentuk inilah yang paling sering kita pakai sehari-hari, termasuk saat memanggil fetch() untuk mengambil data jaringan di section Network.
Kabar baiknya, tidak ada mesin baru yang perlu dipelajari. async-await adalah gula sintaksis di atas promise yang sudah kita kuasai — state, then, dan catch tetap bekerja di balik layar.
async Mengubah Function Menjadi Promise #
Menambahkan kata async di depan function mengubah kontrak kembaliannya:
- Function async selalu mengembalikan promise, apa pun isi
return-nya. - Nilai yang di-
returndibungkus menjadi nilai fulfilled. - Error yang dilempar di dalamnya menjadi alasan rejected.
Ketiga poin ini kita buktikan langsung di bagian 1 berkas contoh. Perhatikan bahwa pemanggil ambilMenu() tidak menerima string, melainkan instance Promise — untuk membaca isinya, pemanggil tetap memakai then, atau await yang kita bahas sesudah ini.
await: Jeda di Dalam Function #
await hanya sah di dalam function async. Ketika runtime menemui await diikuti promise, eksekusi function itu dijeda sampai promise selesai, dan nilainya diteruskan ke variabel. Yang dijeda hanya function pemanggilnya — thread dan kode lain tetap berjalan, sesuai aturan event loop.
Berkas contoh berikut merangkum tiga perilaku: kembalian async function, dua await berurutan, dan try-catch untuk kegagalan:
// async-await-dasar.js
// async function, await, dan try-catch.
function tunggu(ms, nilai) {
return new Promise((resolve) => setTimeout(() => resolve(nilai), ms));
}
// --- 1. async function selalu mengembalikan Promise ---
async function ambilMenu() {
return "Kopi susu, teh tarik, roti bakar";
}
const hasil = ambilMenu();
console.log("kembalian ambilMenu:", hasil instanceof Promise);
hasil.then((menu) => console.log("isi promise:", menu));
// --- 2. await: menunggu promise di dalam async function ---
async function layaniBudi() {
const minuman = await tunggu(20, "kopi susu");
const makanan = await tunggu(20, "roti bakar");
console.log("Budi menerima:", minuman, "+", makanan);
}
layaniBudi();
// --- 3. try-catch menangkap reject dari await ---
async function layaniSiti() {
const pesanan = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error("Stok teh tarik habis")), 10);
});
try {
const minuman = await pesanan;
console.log("Siti menerima:", minuman);
} catch (error) {
console.log("Siti:", error.message);
}
}
layaniSiti();Output yang Dihasilkan:
kembalian ambilMenu: true
isi promise: Kopi susu, teh tarik, roti bakar
Siti: Stok teh tarik habis
Budi menerima: kopi susu + roti bakarMari kita telaah baris-baris pentingnya:
- Baris 9–11 (
ambilMenu): function biasa yang ditandaiasync; isireturn-nya hanya string biasa. - Baris 13–14 (pemanggilan dan uji):
instanceof Promisemenghasilkantrue— runtime membungkus kembalian function async menjadi promise secara otomatis. - Baris 16 (membaca isi): pemanggil membaca nilai lewat
then, bukti bahwa kembalianambilMenumemang promise biasa yang bisa dirantai. - Baris 20–21 (
layaniBudi): duaawaitberurutan. Baris kedua baru dieksekusi setelah baris pertama selesai, sehingga total waktunya adalah jumlah kedua jeda. - Baris 29–31 (pesanan Siti): promise yang sengaja dibuat gagal lewat
rejectdari callback timer. - Baris 32–37 (
try-catch):awaityang menemui promise rejected berperilaku sepertithrow— blokcatchmenangkapnya. Dengan begitu,try-catchdari section Error Handling kembali bekerja untuk kode asinkron. - Baris 40 (pemanggilan tanpa await):
layaniBudi()danlayaniSiti()dipanggil tanpaawait— sah, karena function async berjalan sendiri; di sini kita sengaja tidak menunggu hasilnya.
await pada Nilai yang Bukan Promise #
await tidak menuntut promise. Bila nilai yang mengikutinya bukan promise, nilai itu diteruskan begitu saja tanpa jeda:
async function cobaAwaitNilaiBiasa() {
const angka = await 42; // bukan promise: langsung diteruskan
console.log("await pada nilai biasa:", angka);
}
cobaAwaitNilaiBiasa();Output yang Dihasilkan:
await pada nilai biasa: 42Sifat ini membuat await aman dipakai pada function yang kembaliannya kadang promise, kadang nilai biasa — tidak perlu memeriksa tipe secara manual terlebih dahulu.
Berurutan vs Paralel #
Dua await yang ditulis berurutan berjalan satu demi satu. Bila kedua pekerjaan tidak saling bergantung, urutan seperti ini membuang waktu: pekerjaan kedua sebenarnya bisa dimulai bersamaan. Cara paralelnya sederhana — mulai kedua promise lebih dulu, lalu await keduanya sekaligus dengan Promise.all:
function tunggu(ms, nilai) {
return new Promise((resolve) => setTimeout(() => resolve(nilai), ms));
}
async function berurutan() {
const awal = Date.now();
const a = await tunggu(20, "A");
const b = await tunggu(20, "B");
return { hasil: a + b, durasi: Date.now() - awal };
}
async function paralel() {
const awal = Date.now();
const [a, b] = await Promise.all([tunggu(20, "A"), tunggu(20, "B")]);
return { hasil: a + b, durasi: Date.now() - awal };
}
async function main() {
const hasilBerurutan = await berurutan();
const hasilParalel = await paralel();
console.log("berurutan:", hasilBerurutan.hasil);
console.log("paralel :", hasilParalel.hasil);
console.log(
"durasi berurutan lebih lama dari paralel:",
hasilBerurutan.durasi > hasilParalel.durasi
);
}
main();Output yang Dihasilkan:
berurutan: AB
paralel : AB
durasi berurutan lebih lama dari paralel: trueHasil kedua gaya sama, tetapi waktu berurutan sekitar dua kali lipat waktu paralel. Durasi dalam milidetik memang bervariasi antar mesin, itulah alasan keluaran membandingkan keduanya lewat boolean, bukan angka. Aturan praktisnya: await berurutan untuk langkah yang saling bergantung, Promise.all untuk pekerjaan mandiri. Kombinator lainnya dibedah khusus di chapter Promise Combinators.
Aturan await yang Perlu Diingat #
Empat poin berikut menutup celah kebingungan yang paling sering muncul:
awaithanya sah di dalam function async.awaitpada nilai bukan promise tetap menghasilkan nilai itu.- Error di dalam function async — baik lewat
throwmaupunawaityang gagal — menjadi promise rejected yang harus ditangkap pemanggilnya dengancatchatautry-catch. - Lupa menangkap rejection berarti membiarkan kegagalan tanpa penanganan; akibatnya dibedah tuntas di chapter Error Handling Asynchronous Code.
Dengan async-await, menulis alur asinkron terasa seperti menulis kode sinkron. Tinggal satu kelompok alat yang belum kita sentuh: menggabungkan banyak promise sekaligus — all, allSettled, race, dan any.
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
async-await-dasar.js
Unduh berkas// async-await-dasar.js
// async function, await, dan try-catch.
function tunggu(ms, nilai) {
return new Promise((resolve) => setTimeout(() => resolve(nilai), ms));
}
// --- 1. async function selalu mengembalikan Promise ---
async function ambilMenu() {
return "Kopi susu, teh tarik, roti bakar";
}
const hasil = ambilMenu();
console.log("kembalian ambilMenu:", hasil instanceof Promise);
hasil.then((menu) => console.log("isi promise:", menu));
// --- 2. await: menunggu promise di dalam async function ---
async function layaniBudi() {
const minuman = await tunggu(20, "kopi susu");
const makanan = await tunggu(20, "roti bakar");
console.log("Budi menerima:", minuman, "+", makanan);
}
layaniBudi();
// --- 3. try-catch menangkap reject dari await ---
async function layaniSiti() {
const pesanan = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error("Stok teh tarik habis")), 10);
});
try {
const minuman = await pesanan;
console.log("Siti menerima:", minuman);
} catch (error) {
console.log("Siti:", error.message);
}
}
layaniSiti();