Callback menjawab kebutuhan menjalankan kode setelah pekerjaan yang harus ditunggu selesai, tetapi pekerjaan yang berantai cepat berubah menjadi bersarang dan sulit diikuti. Promise menawarkan alternatif lebih rapi, yaitu objek yang mewakili hasil pekerjaan yang belum tentu tersedia saat ini. Objek ini memiliki tiga status dan cara penanganan yang seragam. Topik ini membangun promise melalui fungsi yang disebut executor, mengulas tiga statusnya, lalu mempraktikkan then, catch, finally, dan perangkaian nilai baliknya. Setelah membacanya, pekerjaan tunggu seperti timer dapat dibungkus menjadi promise dan hasilnya diolah berantai tanpa bersarang.
Tiga status promise#
Sebuah promise selalu berada di salah satu dari tiga status. Status awalnya adalah pending, yakni pekerjaan masih berjalan dan hasilnya belum ada. Ketika pekerjaannya berhasil, statusnya bergerak ke fulfilled sambil membawa nilai hasilnya. Ketika pekerjaannya gagal, statusnya bergerak ke rejected sambil membawa alasan, biasanya berupa objek Error. Pergerakannya hanya satu arah, dan perpindahan dari pending menuju fulfilled atau rejected disebut settled, yakni keadaan ketika status promise sudah final.
| Status | Makna | Membawa |
|---|---|---|
pending | pekerjaan masih berjalan | belum ada nilai maupun alasan |
fulfilled | pekerjaan berhasil | nilai hasil pekerjaan |
rejected | pekerjaan gagal | alasan, biasanya objek Error |
Sifat sekali bergerak inilah yang membuat promise aman dipakai. Callback tidak mungkin terpanggil dua kali dengan hasil berbeda, dan kode yang menerima promise tidak perlu memeriksa ulang statusnya setiap saat.
Status tidak dapat dibaca langsung dari luarnya, dan tidak ada properti bawaan yang menyatakan sebuah promise sedang pending atau sudah fulfilled. Satu-satunya cara mengamatinya adalah mendaftarkan callback lewat then, catch, dan finally. Callback itu dipanggil ketika status bergerak, atau langsung saat didaftarkan bila pergerakan sudah terjadi. Desain ini membuat kode penanganan tetap benar tanpa peduli seberapa cepat pekerjaan selesai. Callback yang terdaftar belakangan pun tetap dipanggil dengan hasil yang sudah terkunci.
Membuat promise dari pekerjaan yang menunggu#
Promise dibuat dengan new Promise(executor), dan executor adalah fungsi yang langsung menerima dua parameter, yaitu resolve dan reject. Memanggil resolve(nilai) memindahkan promise ke fulfilled dengan nilai tersebut, sedangkan reject(alasan) memindahkannya ke rejected. Executor sendiri berjalan segera saat promise dibuat, bukan ketika hasilnya dibutuhkan, sehingga pekerjaan di dalamnya dimulai begitu baris itu dieksekusi.
// Promise yang diselesaikan oleh timer setelah penundaan singkat.
function tunggu(ms) {
return new Promise((resolve) => {
setTimeout(() => resolve("selesai menunggu " + ms + " ms"), ms);
});
}
tunggu(40).then((pesan) => {
console.log("terpenuhi:", pesan);
});
console.log("promise masih pending, kode di bawahnya tetap berjalan");promise masih pending, kode di bawahnya tetap berjalan
terpenuhi: selesai menunggu 40 msFungsi tunggu di atas adalah pola yang layak diingat, timer setTimeout dibungkus promise sehingga hasilnya dapat dirangkai lewat then. Selama 40 milidetik berjalan, promise-nya berstatus pending dan kode di bawahnya tetap berjalan seperti keluaran tersebut. Begitu callback timer memanggil resolve, statusnya berpindah ke fulfilled dan callback then yang terdaftar dipanggil dengan pesan hasilnya.
Menampung hasil dengan then, catch, dan finally#
Penanganan hasil promise dilakukan dengan tiga metode yang saling menyambung. then menerima callback untuk keberhasilan, catch menerima callback untuk kegagalan, dan finally menerima callback tanpa argumen. Callback finally selalu berjalan baik berhasil maupun gagal, cocok untuk pembersihan seperti menutup indikator tunggu. Program berikut menguji dua arah sekaligus, satu pembagian yang berhasil dan satu yang gagal.
// then menampung keberhasilan, catch menampung kegagalan, finally selalu berjalan.
function bagi(a, b) {
return new Promise((resolve, reject) => {
if (b === 0) {
reject(new Error("pembagi tidak boleh nol"));
} else {
resolve(a / b);
}
});
}
bagi(10, 2)
.then((hasil) => console.log("hasil:", hasil))
.catch((err) => console.log("error:", err.message))
.finally(() => console.log("hitungan pertama selesai"));
bagi(7, 0)
.then((hasil) => console.log("hasil:", hasil))
.catch((err) => console.log("error:", err.message))
.finally(() => console.log("hitungan kedua selesai"));hasil: 5
error: pembagi tidak boleh nol
hitungan pertama selesai
hitungan kedua selesaiPembagian pertama menempuh jalur then dan mencetak hasilnya, sedangkan yang kedua jatuh ke catch karena executor-nya memanggil reject. Baris finally tercetak pada keduanya, bukti bahwa pembersihan berjalan tanpa peduli arah hasilnya.
Peragaan berikut memperlihatkan perpindahan statusnya di browser, tekan tombolnya lalu perhatikan dua baris yang muncul berurutan.
Kode sumber demo
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<title>Demo status promise</title>
<style>
body { font-family: "Segoe UI", Arial, sans-serif; margin: 14px; font-size: 14px; color: #1f2937; }
button { padding: 6px 12px; margin-right: 8px; margin-bottom: 10px; cursor: pointer; }
pre { font-size: 13px; line-height: 1.7; background: #f3f4f6; padding: 10px; min-height: 80px; }
</style>
</head>
<body>
<p>Tekan tombolnya dan perhatikan dua baris yang muncul berurutan.</p>
<button id="tombol-jalankan" type="button">Jalankan janji</button>
<pre id="log"></pre>
<script src="index.js"></script>
<script>
// Demo status promise, dari pending menuju fulfilled.
const log = document.getElementById("log");
function catat(pesan) {
log.textContent = log.textContent + pesan + "\n";
}
document.getElementById("tombol-jalankan").addEventListener("click", () => {
log.textContent = "";
catat("klik diterima, promise dibuat dan masih menunggu");
const janji = new Promise((resolve) => {
setTimeout(() => resolve("data sudah siap"), 800);
});
janji.then((hasil) => {
catat("800 ms berlalu, promise terpenuhi dengan hasil: " + hasil);
});
});
</script>
<script>
// Demo status promise, dari pending menuju fulfilled.
const log = document.getElementById("log");
function catat(pesan) {
log.textContent = log.textContent + pesan + "\n";
}
document.getElementById("tombol-jalankan").addEventListener("click", () => {
log.textContent = "";
catat("klik diterima, promise dibuat dan masih menunggu");
const janji = new Promise((resolve) => {
setTimeout(() => resolve("data sudah siap"), 800);
});
janji.then((hasil) => {
catat("800 ms berlalu, promise terpenuhi dengan hasil: " + hasil);
});
});
</script></body>
</html>Merangkai nilai lewat rantai then#
Kekuatan utama promise ada pada nilai balik then, yang bukan sekadar nilai, melainkan promise baru. Nilai biasa yang dikembalikan dari callback then menjadi nilai terpenuhi bagi tautan berikutnya, sehingga pengolahan bertahap dapat ditulis lurus ke bawah. Bila callback mengembalikan promise, rantai menunggu promise itu selesai terlebih dahulu sebelum melanjutkan, sehingga pekerjaan bertingkat pun tetap lurus tanpa bersarang.
// Nilai balik dari sebuah then menjadi masukan then berikutnya.
function tunggu(ms, nilai) {
return new Promise((resolve) => setTimeout(() => resolve(nilai), ms));
}
tunggu(10, 2)
.then((angka) => angka * 10)
.then((angka) => angka + 5)
.then((hasil) => console.log("hasil akhir:", hasil));hasil akhir: 25Angka 2 keluar dari timer, dikalikan sepuluh menjadi 20 pada tautan pertama, lalu ditambah lima menjadi 25 pada tautan kedua. Alur yang setara bila ditulis dengan callback akan bersarang dua tingkat, sedangkan bentuk rantainya tetap satu kolom dari atas ke bawah.
Rantai yang sama juga menjadi jalur kegagalan. Callback yang melempar error, atau promise yang ditolak di tengah rantai, membuat tautan berikutnya terlewati sampai catch terdekat menemukannya. Setelah catch menampung, rantai dapat bersambung lagi dengan nilai hasil penanganannya. Dengan begitu, satu catch di ujung cukup untuk seluruh alur, dan error dari tautan mana pun tidak pernah lolos tanpa penanganan.
Ringkasan#
- Promise mewakili hasil pekerjaan asinkron dengan tiga status, yaitu pending, fulfilled, dan rejected.
- Executor berjalan segera saat promise dibuat, dan pemanggilan
resolveataurejectmengunci statusnya untuk selamanya. thenmenampung keberhasilan,catchmenampung kegagalan, danfinallyselalu berjalan untuk pembersihan.- Nilai balik
thenmenjadi masukan tautan berikutnya, sehingga alur panjang tertulis berantai tanpa bersarang.
Referensi#
- Promise — MDN Web Docs — dokumentasi resmi promise, termasuk tiga status dan constructor-nya.
- Using promises — MDN Web Docs — panduan pemakaian then dan catch dalam praktik.
- Promise basics — The Modern JavaScript Tutorial — bab yang merinci executor, status, dan penanganannya.