Bir API isteğinin ne zaman tamamlanacağını, dosyanın ne zaman okunacağını veya kullanıcının konum bilgisinin ne zaman geleceğini önceden bilemeyiz. JavaScript bu bekleme süresinde uygulamayı durdurmak yerine diğer işleri yürütür. Ancak sonuçları callback fonksiyonlarıyla takip etmeye çalışmak, kısa sürede girintilerle dolu bir “callback cehennemine” dönüşebilir. Promise nesneleri, gelecekte tamamlanacak işlemleri düzenli, zincirlenebilir ve güvenilir biçimde temsil ederek bu karmaşaya çözüm sunar.
``
Promise nedir?
Promise, henüz elimizde olmayan fakat gelecekte elde edilmesi beklenen bir değerin temsilcisidir. Gerçek hayatta restorandan aldığımız sipariş fişine benzetilebilir: Yemek henüz hazır değildir, ancak fiş işlemin başarılı şekilde tamamlanacağını veya bir sorun oluşacağını takip etmemizi sağlar.
Bir Promise üç durumdan birinde bulunur:
| Durum | Anlamı | Sonraki adım |
|---|---|---|
pending |
İşlem devam ediyor | Beklenir |
fulfilled |
İşlem başarıyla tamamlandı | Değer kullanılır |
rejected |
İşlem başarısız oldu | Hata işlenir |
Bir Promise yalnızca bir kez sonuçlanır. fulfilled veya rejected durumuna geçtikten sonra tekrar değiştirilemez. Durum geçişini matematiksel olarak $pending \rightarrow fulfilled$ veya $pending \rightarrow rejected$ biçiminde gösterebiliriz. Ancak $fulfilled \rightarrow pending$ gibi bir geri dönüş mümkün değildir.
İlk Promise’imizi oluşturalım
Promise kurucusu, resolve ve reject fonksiyonlarını alan bir yürütücü fonksiyon bekler:
function siparisHazirla(stokVarMi) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (stokVarMi) {
resolve({ urun: "Kahve", durum: "Hazır" });
} else {
reject(new Error("Kahve çekirdeği kalmadı!"));
}
}, 1000);
});
}
Burada setTimeout, bir saniye süren asenkron işlemi taklit eder. İşlem başarılıysa resolve sonuç değerini iletir; başarısızsa reject bir hata üretir. Gerçek projelerde aynı yapı ağ istekleri, veritabanı sorguları veya dosya işlemleri için kullanılabilir.
Promise sonucunu then, catch ve finally metotlarıyla yönetebiliriz:
siparisHazirla(true)
.then((siparis) => {
console.log(siparis.durum);
return `${siparis.urun} müşteriye götürülüyor`;
})
.then((mesaj) => console.log(mesaj))
.catch((hata) => console.error(hata.message))
.finally(() => console.log("Sipariş işlemi sona erdi"));
Her then yeni bir Promise döndürür. Böylece sonuçlar sırayla aktarılır ve iç içe callback’ler yerine düz bir zincir kurulur. Zincirin herhangi bir noktasında hata oluşursa kontrol en yakın catch bloğuna gider. finally ise sonuç ne olursa olsun çalışır; yükleniyor göstergesini kapatmak gibi temizlik işleri için idealdir.
Callback ve Promise karşılaştırması
| Özellik | Callback yaklaşımı | Promise yaklaşımı |
|---|---|---|
| Okunabilirlik | İç içe yapılar oluşabilir | Doğrusal zincir kurulur |
| Hata yönetimi | Her seviyede ayrı kontrol gerekebilir | Tek catch zinciri yakalayabilir |
| Birleştirme | Elle koordinasyon gerekir | Hazır yardımcı metotlar vardır |
| Sonuç aktarımı | Parametrelerle yapılır | return ile zincire iletilir |
Birden fazla işlemi yönetmek
Bağımsız görevleri paralel başlatmak için Promise.all kullanılabilir:
const profil = fetch("/api/profil");
const bildirimler = fetch("/api/bildirimler");
Promise.all([profil, bildirimler])
.then(([profilYaniti, bildirimYaniti]) => {
console.log("İki istek de tamamlandı");
})
.catch((hata) => console.error("İsteklerden biri başarısız", hata));
İşlemlerin süreleri $t_1$ ve $t_2$ ise paralel toplam süre yaklaşık $T = \max(t_1, t_2)$ olur. Sıralı çalıştırmada ise süre yaklaşık $T = t_1 + t_2$ olacaktır. Bununla birlikte Promise.all, tek bir işlem reddedildiğinde hemen reddedilir. Bütün sonuçları başarı veya hata ayrımıyla görmek için Promise.allSettled; ilk tamamlanan sonucu almak için Promise.race; ilk başarılı sonucu almak için Promise.any tercih edilebilir.
Promise’lar işlemleri sihirli biçimde hızlandırmaz; asıl güçleri zamanlamayı ve hata akışını düzenlemeleridir. Modern async/await sözdizimi de temelde Promise’lar üzerinde çalışır. Bu nedenle Promise mantığını öğrenmek, yalnızca eski callback zincirlerinden kurtulmayı değil, JavaScript’in modern asenkron dünyasını sağlam bir temelle anlamayı sağlar.
Yorumlar