Promise.allSettled dan Promise.all sama-sama menjalankan banyak promise sekaligus, tetapi cara keduanya bereaksi saat ada yang gagal sangat berbeda. Perbedaan kecil ini sering jadi penyebab bug yang membingungkan: satu API error, lalu seluruh halaman gagal tampil padahal data lainnya sudah berhasil diambil.
Bayangkan kamu membuat halaman dashboard yang memuat profil, notifikasi, dan statistik dari tiga endpoint berbeda. Server notifikasi sedang bermasalah. Haruskah seluruh dashboard ikut gagal? Di sinilah Promise.allSettled berguna. Artikel ini membahas cara kerja keduanya, lima perbedaan utamanya, dan kapan sebaiknya memilih salah satunya.
(Sisipkan blok Table of Contents Rank Math di sini.)
Apa Itu Promise.all?
Promise.all() menerima kumpulan promise (biasanya array) dan mengembalikan satu promise baru. Promise baru itu berhasil jika semua promise berhasil, dan hasilnya berupa array nilai dengan urutan yang sama seperti input. Namun jika satu saja promise gagal, Promise.all() langsung ditolak dengan alasan dari promise yang gagal itu. Perilaku ini disebut fail-fast.
const tugas = [
Promise.resolve('profil'),
Promise.reject(new Error('Server notifikasi down')),
Promise.resolve('statistik'),
];
try {
const hasil = await Promise.all(tugas);
console.log(hasil);
} catch (error) {
console.log(error.message); // 'Server notifikasi down'
}
Perhatikan bahwa ‘profil’ dan ‘statistik’ sebenarnya berhasil, tetapi kamu tidak bisa mengaksesnya lagi karena Promise.all() hanya melaporkan kegagalan pertama.
Apa Itu Promise.allSettled?
Promise.allSettled() menunggu semua promise selesai, baik berhasil maupun gagal, lalu mengembalikan array berisi objek yang menjelaskan hasil tiap promise. Fitur ini diperkenalkan di ES2020 dan didukung browser modern serta Node.js 12.9 ke atas.
Setiap objek hasil punya dua kemungkinan bentuk:
{ status: 'fulfilled', value: ... }untuk promise yang berhasil{ status: 'rejected', reason: ... }untuk promise yang gagal
const hasil = await Promise.allSettled(tugas);
console.log(hasil);
// [
// { status: 'fulfilled', value: 'profil' },
// { status: 'rejected', reason: Error('Server notifikasi down') },
// { status: 'fulfilled', value: 'statistik' }
// ]
Selama inputnya valid, promise yang dikembalikan Promise.allSettled() tidak ditolak karena satu promise gagal. Kamu yang menentukan apa yang dilakukan dengan setiap hasil.
Contoh Nyata: Memuat Dashboard dari 3 API
Berikut penerapan Promise.allSettled pada kasus dashboard tadi. Perhatikan helper ambilData: fungsi fetch tidak menolak promise saat server mengembalikan status 404 atau 500, jadi kita perlu melempar error sendiri.
async function ambilData(url) {
const res = await fetch(url);
if (!res.ok) throw new Error('Gagal memuat ' + url);
return res.json();
}
async function muatDashboard() {
const [profil, notifikasi, statistik] = await Promise.allSettled([
ambilData('/api/profil'),
ambilData('/api/notifikasi'),
ambilData('/api/statistik'),
]);
return {
profil: profil.status === 'fulfilled' ? profil.value : null,
notifikasi: notifikasi.status === 'fulfilled' ? notifikasi.value : [],
statistik: statistik.status === 'fulfilled' ? statistik.value : null,
};
}
Dengan pola ini, dashboard tetap tampil meskipun satu bagian gagal. Bagian yang gagal bisa diganti pesan “Data belum tersedia”. Saat mengakses data yang mungkin null, optional chaining JavaScript membantu menghindari error Cannot read properties of undefined.
5 Perbedaan Promise.allSettled vs Promise.all
| No | Aspek | Promise.all | Promise.allSettled |
|---|---|---|---|
| 1 | Saat ada promise gagal | Langsung ditolak (fail-fast) | Tetap menunggu semua selesai |
| 2 | Bentuk hasil | Array nilai | Array objek { status, value / reason } |
| 3 | Bisa ditolak? | Ya, jika satu promise gagal | Tidak, selama input valid |
| 4 | Kecepatan | Selesai saat kegagalan pertama atau semua berhasil | Selalu menunggu promise paling lambat |
| 5 | Cocok untuk | Semua langkah wajib berhasil | Keberhasilan sebagian dapat diterima |
Satu catatan penting: pada kedua metode, urutan hasil mengikuti urutan input, bukan urutan promise selesai. Selain itu, saat Promise.all() ditolak, promise lain tidak dibatalkan. Mereka tetap berjalan di latar belakang, hanya hasilnya yang diabaikan.
Kapan Memakai Promise.allSettled?
Pilih Promise.allSettled ketika kegagalan sebagian bukan akhir dunia:
- Dashboard atau halaman dengan banyak widget, seperti contoh di atas.
- Pengiriman massal, misalnya mengirim email atau notifikasi ke banyak pengguna lalu melaporkan berapa yang gagal.
- Sinkronisasi data dari beberapa sumber, ketika sumber yang gagal bisa dicoba ulang nanti.
- Pemeriksaan kesehatan (health check) beberapa layanan sekaligus.
Contoh membuat laporan sukses dan gagal:
const hasil = await Promise.allSettled(daftarTugas);
const berhasil = hasil.filter((h) => h.status === 'fulfilled').length;
const gagal = hasil.filter((h) => h.status === 'rejected');
console.log(berhasil + ' berhasil, ' + gagal.length + ' gagal');
gagal.forEach((g) => console.error(g.reason));
Kapan Tetap Memakai Promise.all?
Promise.all lebih tepat jika hasilnya hanya berguna bila semua langkah sukses. Contohnya: memuat konfigurasi, data pengguna, dan izin akses sebelum aplikasi boleh berjalan, atau menjalankan beberapa langkah validasi yang semuanya harus lolos. Dalam kasus seperti ini, fail-fast justru menguntungkan karena kamu bisa berhenti lebih cepat dan menampilkan error.
Jika terlalu banyak request dijalankan paralel, server bisa kewalahan atau kamu terkena pembatasan. Pelajari pengamanannya di artikel rate limiting API di Express.
Bagaimana dengan Promise.race dan Promise.any?
Ada dua metode lain yang sering tertukar:
Promise.race()mengikuti promise pertama yang selesai, berhasil atau gagal.Promise.any()mengikuti promise pertama yang berhasil. Jika semuanya gagal, hasilnya adalahAggregateError.
Ringkasnya: all untuk “semua harus sukses”, allSettled untuk “saya ingin semua hasilnya”, race untuk “yang tercepat”, dan any untuk “yang pertama berhasil”.
Kesalahan Umum Saat Memakai Promise.allSettled
- Lupa memeriksa
status. Mengakses.valuepada hasil yangrejectedakan menghasilkanundefined. - Mengira fetch gagal pada status 404 atau 500. Tanpa
res.ok, promise tetap dianggap berhasil. - Menunggu satu per satu. Memakai
awaitberurutan di dalam loop membuat request berjalan serial dan lebih lambat. Mulai semua promise lebih dulu, lalu tunggu bersama. - Tidak menangani alasan kegagalan. Simpan atau catat
reasonagar bug mudah dilacak, sama seperti prinsip kode yang mudah dibaca di artikel code readability.
Pertanyaan yang Sering Diajukan (FAQ)
Apakah Promise.allSettled lebih lambat dari Promise.all? Tidak selalu. Pada skenario semua promise berhasil, keduanya selesai pada waktu yang hampir sama. Perbedaan terasa saat ada kegagalan: Promise.all selesai lebih awal karena langsung ditolak, sedangkan Promise.allSettled tetap menunggu promise paling lambat.
Apakah Promise.allSettled pernah menolak? Promise yang dikembalikannya tidak ditolak karena kegagalan promise di dalamnya. Namun jika kamu memberikan input yang bukan iterable, JavaScript akan melempar error TypeError.
Bagaimana urutan hasil Promise.allSettled? Urutannya sama dengan urutan promise pada input, bukan urutan selesainya.
Apakah Promise.allSettled bisa dipakai di semua browser? Semua browser modern dan Node.js 12.9 ke atas mendukungnya. Untuk lingkungan lama, gunakan polyfill atau transpiler. Detail kompatibilitas ada di dokumentasi MDN tentang Promise.allSettled.
Kesimpulan
Promise.allSettled dan Promise.all menjawab dua kebutuhan berbeda. Pakai Promise.all saat semua langkah wajib berhasil dan kegagalan satu langkah berarti seluruh proses gagal. Pakai Promise.allSettled saat kamu ingin semua hasil, termasuk yang gagal, supaya aplikasi tetap berjalan meski sebagian data bermasalah. Dengan memahami lima perbedaan di atas, kamu bisa memilih metode yang tepat dan menghindari bug yang sulit dilacak.
Coba ubah satu kode Promise.all di proyekmu menjadi Promise.allSettled, lalu amati perbedaannya saat salah satu request sengaja digagalkan. Praktik langsung adalah cara tercepat untuk benar-benar memahaminya.