Mengapa JavaScript forEach() Tidak Bekerja dengan await (Dan Bagaimana Memperbaikinya)
Salah satu masalah paling membingungkan dalam penggunaan async di JavaScript adalah ketika developer menggunakan await di dalam forEach() dan mengharapkan semua proses berjalan secara berurutan.
Masalahnya
Misalnya, Anda ingin mengirim email kepada pengguna satu per satu. Anda menulis kode seperti ini:
const users = ["John", "Emma", "Michael"];
users.forEach(async (user) => {
await sendEmail(user);
console.log(`Email sent to ${user}`);
});
console.log("All emails processed");
Pada awalnya, kode ini terlihat sempurna. Anda mengharapkan proses berjalan seperti ini:
- Mengirim email kepada John
- Mengirim email kepada Emma
- Mengirim email kepada Michael
- Mencetak pesan "All emails processed"
Namun, output yang sebenarnya seringkali tidak seperti itu. Bahkan, eksekusi bisa menjadi tidak terprediksi.
Mengapa Ini Terjadi
Masalahnya adalah forEach() tidak menunggu proses async/await. forEach() mengabaikan Promises yang ada di dalamnya. Bahkan jika Anda menulis await di dalamnya, forEach() sendiri tidak akan berhenti. Ini berarti bahwa baris kode console.log("All emails processed"); akan dijalankan sebelum proses async selesai.
Memperbaiki Masalah
Solusi yang paling aman adalah menggunakan for...of. Contohnya seperti ini:
const users = ["John", "Emma", "Michael"];
async function processUsers() {
for (const user of users) {
await sendEmail(user);
console.log(`Email sent to ${user}`);
}
console.log("All emails processed");
}
processUsers();
Dengan menggunakan for...of, JavaScript akan menunggu proses sebelumnya selesai sebelum melanjutkan ke proses berikutnya.
Jika Anda Ingin Eksekusi Paralel
Terkadang, Anda memang ingin menjalankan proses secara paralel. Untuk itu, Anda bisa menggunakan Promise.all(). Contohnya seperti ini:
const users = ["John", "Emma", "Michael"];
await Promise.all(
users.map(async (user) => {
await sendEmail(user);
console.log(`Email sent to ${user}`);
})
);
console.log("All emails processed");
Dengan Promise.all(), Anda bisa menjalankan proses secara paralel tetapi masih menunggu semua proses selesai sebelum melanjutkan.
Kesimpulan
forEach() memang excellent untuk loop sederhana yang bersifat sinkron. Namun, untuk workflow async, forEach() bisa menjadi berbahaya. Ingatlah bahwa forEach() mengabaikan await, for...of menangani urutan dengan aman, dan Promise.all() menangani pekerjaan paralel dengan benar. Dengan memahami ini, kode async JavaScript Anda akan menjadi lebih rapi dan bug di produksi akan lebih mudah dicegah.



