JavaScript Promise Nedir?
JavaScript Promise kavramı temelden: sözcük anlamı, üç durumu (pending/fulfilled/rejected), .then().catch() zinciri, Promise.all/Promise.race, callback hell'den kurtuluş. SSS, benzetmeler, mülakat tuzakları.
Closetrafi bosalt
Promise JavaScript'in asenkron programlama dünyasının kapısı. async/await ne kadar konuşulursa konuşulsun, Promise olmadan anlamı kalmaz. Çünkü async/await sadece Promise'leri yazmanın "daha temiz" bir yolu. Önce Promise'i anlamadan async/await "sihir gibi" kalır.
Mulakatlarda Promise denince akla 4-5 farklı soru gelir: Promise nedir, callback hell'den farkı ne, .then() nasıl çalışır, Promise.all ne zaman kullanılır, hata yönetimi nasıl yapılır. Bu yazıda hepsini temelden, örneklerle, benzetmelerle anlatıyoruz. Once yalin ifadeyle: Promise, "şimdi veremiyorum ama söz veriyorum, birazdan vereceğim" diyen bir nesnedir.
Benzetme: Kahve siparişi
Promise'i bir kahveci düşünerek anlatayım. Sen kafeye girdin, sırada bekliyorsun, kasiyer sana bir fiş numarası verdi. "Numaran 42, kahven hazır olunca ekranda görünecek." Sen bu fiş numarasıyla masaya oturdun, başka iş yaptın (telefona baktın, konuştun). 5 dakika sonra ekranda "42 numara hazır" yandı. Kalkıp kahveni aldın.
İşte Promise tam olarak bu fiş numarası:
- Fiş numarası =
new Promise(...)— henüz kahve yok ama söz var. - "42 hazır" yandı =
resolve(kahve)— söz tutuldu, değer geldi. - "Süt bitti, kahve yok" =
reject(hata)— söz tutulamadı, hata oldu. - Ekranı kontrol etmek =
.then(...)veya.catch(...)— sonucu almak için yapılan çağrı.
Sen fiş numarasını alıp oturduğunda, kasiyer seni beklemiyor (JavaScript tek iş parçacıklı çalışıyor, bloklanamaz). Başka müşterilere bakıyor. Senin kahven hazır olunca ekrana yansıtıyor. Sen de "hazır olunca" diye bir kod yazdın, sistem otomatik çalıştırdı. İşte asenkron programlamanın özü bu.
Promise'in üç durumu (state)
Her Promise yaşamı boyunca üç durumdan birinde olur. Bu durumlar Promise'in iç dünyasıdır, dışarıdan sadece sonucu (değer veya hata) görürsün:
resolve(değer) çağrıldı. "Kahven hazır, afiyet olsun."reject(hata) çağrıldı. "Süt bitti, kahve yok."Önemli kural: Bir Promise yalnızca bir kez state değiştirebilir. pending → fulfilled VEYA pending → rejected. Sonra bir daha değişmez (immutable). Yani bir Promise hem başarılı hem hatalı olamaz, sadece biri.
İlk Promise'in
En basit Promise'i yazalım: 1 saniye sonra "Merhaba" diyen bir söz.
const mesaj = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Merhaba dünya!"); // 1 saniye sonra "söz tutuldu"
}, 1000);
});
console.log(mesaj); // Promise { <pending> }
// 1 saniye sonra:
mesaj.then((sonuc) => console.log(sonuc)); // "Merhaba dünya!"Gördüğün gibi: new Promise((resolve, reject) => ...) bir nesne yaratır. İçine verdiğin fonksiyon executor denir. resolve başarı durumunu temsil eder (değerle çağrılır), reject hata durumunu temsil eder (hata objesiyle çağrılır). Henüz hiçbiri çağrılmadığı için Promise pending durumunda.
Callback → Promise evrimi (callback hell'den kurtuluş)
Promise'den önce asenkron kod callback fonksiyonlarıyla yazılıyordu. Bu özellikle "3-4 asenkron iş art arda" yapıldığında içinden çıkılmaz bir hal alıyordu. Buna callback hell (callback cehennemi) denir.
Önce: Callback hell
Diyelim: kullanıcı ID'si var → kullanıcı bilgisi çek → o kullanıcının siparişlerini çek → ilk siparişin detayını çek. Callback ile:
// ❌ Callback hell — sağa doğru kayıyor, okunamaz
kullaniciGetir(42, (hata, kullanici) => {
if (hata) return console.log(hata);
siparisleriGetir(kullanici.id, (hata, siparisler) => {
if (hata) return console.log(hata);
siparisDetay(siparisler[0].id, (hata, detay) => {
if (hata) return console.log(hata);
console.log(detay);
// 3 seviye iç içe, hâlâ devam edebilir...
});
});
});Sonra: Promise zinciri (düz, okunabilir)
Aynı iş, Promise ile sağa değil aşağı uzanır. Her adım düz bir satır:
// ✅ Promise zinciri — aşağı doğru, okunabilir
kullaniciGetir(42)
.then((kullanici) => siparisleriGetir(kullanici.id))
.then((siparisler) => siparisDetay(siparisler[0].id))
.then((detay) => console.log(detay))
.catch((hata) => console.log(hata)); // tek bir catch, tüm zinciri korurFarkı gördün mü? Callback'de her adım için ayrı hata kontrolü vardı, iç içe geçmişti. Promise'de tek bir .catch() tüm zincirdeki hatayı yakalar. Bu, "bir hata olursa tüm zincir durur" demektir. Mülakatlarda bu pattern'i bilmek büyük artı.
Modern projelerde artık async/await kullanılıyor (Promise'in syntactic sugar'ı). Ama Promise mantığını anlamadan async/await "sihir" gibi kalır. Bu yüzden önce Promise, sonra async/await öğren.
.then() / .catch() / .finally() — üçlü
Promise'in sonucunu almak için 3 metod var. Hepsi birer fonksiyon alır, hepsi yeni bir Promise döner (zincir kurabilirsin).
.then(başarı, hata?)
Promise resolve olduğunda çalışır. Veriyi alırsın. İstersen ikinci parametre olarak hata fonksiyonu da geçebilirsin ama tavsiye edilmez, .catch() daha temiz.
fetch("/api/user")
.then((cevap) => cevap.json())
.then((user) => console.log("Kullanıcı:", user));.catch(hata)
Promise reject olduğunda veya zincirde herhangi bir .then() hata fırlattığında çalışır. Tüm hataları tek noktada yakalar. JavaScript'te standart hata yönetimi.
fetch("/api/user")
.then((c) => c.json())
.catch((hata) => console.error("Bir şeyler ters gitti:", hata));.finally(cleanup)
Başarı veya hata fark etmez, her durumda çalışır. Genelde "yükleniyor" göstergesini kapatmak, bağlantıyı sonlandırmak gibi temizlik işleri için kullanılır.
fetch("/api/user")
.then((c) => c.json())
.catch((hata) => console.error(hata))
.finally(() => {
yukleniyorGizle(); // her durumda çalışır
baglantiKapat(); // her durumda çalışır
});Pratik örnek: fetch + Promise
Gerçek bir örnek: bir kullanıcı bilgisi çekiyoruz. Hata olursa mesaj gösteriyoruz, her durumda "yükleniyor"u kapatıyoruz:
function kullaniciGoster(id) {
yukleniyorGoster();
fetch(`/api/users/${id}`)
.then((cevap) => {
if (!cevap.ok) throw new Error("HTTP " + cevap.status);
return cevap.json(); // yeni Promise, JSON parse
})
.then((user) => {
isimYaz(user.name);
emailYaz(user.email);
})
.catch((hata) => {
hataGoster("Kullanıcı yüklenemedi: " + hata.message);
})
.finally(() => {
yukleniyorGizle();
});
}Promise zinciri (chaining) — .then()'in sihri
.then() her zaman yeni bir Promise döner. Bu sayede zincir kurabilirsin. Bir adımın çıktısı, sonraki adımın girdisi olur.
Veri dönüşümü zinciri
Bir kullanıcı listesi çekip, sadece aktif olanları filtreleyip, isimleri büyük harfe çevirip, ilk 3'ünü alalım:
fetch("/api/users")
.then((c) => c.json()) // [user, user, ...]
.then((users) => users.filter((u) => u.aktif)) // sadece aktif
.then((aktif) => aktif.map((u) => u.name.toUpperCase())) // BUYUK HARF
.then((isimler) => isimler.slice(0, 3)) // ilk 3
.then((ilkUc) => console.log(ilkUc));
// ["AYŞE", "MEHMET", "ZEYNEP"]Sık yapılan hata: zincir kırmak
Yeni başlayanlar sık şu hatayı yapar: zincirde bir yerde Promise döndürmeyi unuturlar. Bu durumda .then() "undefined" alır ve hata fırlatır:
// ❌ Hatalı: .then() içinde Promise DÖNDÜRMEDİN
fetch("/api/users")
.then((c) => c.json())
.then((users) => {
users.filter((u) => u.aktif); // sadece filtreledin, döndürmedin
})
.then((sonuc) => console.log(sonuc)); // undefined!
// ✅ Doğru: return ile döndür
fetch("/api/users")
.then((c) => c.json())
.then((users) => users.filter((u) => u.aktif)) // return otomatik
.then((aktif) => console.log(aktif.length));Süslü parantez kullanıyorsan return şart. Ok fonksiyonu (=>) tek satırsa return otomatik. Süslü parantez açtıysan return yazmayı unutma.
Promise.all, race, allSettled — paralel asenkron
Bazen birden fazla asenkron işi paralel çalıştırmak istersin. Tek tek await etmek yerine toplu metotlar var. Üçü de farklı senaryolarda kullanılır:
Promise.all — hepsi başarılı olmalı
Tüm Promise'ler başarılı olursa sonuçları dizi olarak verir. Bir tanesi bile hata verirse hemen reject olur (fail-fast). En sık kullanılan metot.
// 3 kullanıcıyı paralel çek, hepsi gelince devam et
const [u1, u2, u3] = await Promise.all([
fetch("/api/user/1").then((c) => c.json()),
fetch("/api/user/2").then((c) => c.json()),
fetch("/api/user/3").then((c) => c.json()),
]);
// Toplam süre: en yavaş istek (paralel)
// 3 ayrı await etseydin: 1+2+3 (sıralı)Promise.race — ilk biten kazanır
Hangi Promise ilk resolve veya reject olursa onu döner. "Yarış" gibi. Genelde timeout senaryolarında kullanılır.
// 3 saniye içinde cevap gelmezse iptal et
const veri = await Promise.race([
fetch("/api/yavas-endpoint").then((c) => c.json()),
new Promise((_, reject) =>
setTimeout(() => reject(new Error("Zaman aşımı")), 3000)
),
]);Promise.allSettled — hepsini bekle
Tüm Promise'ler bitene kadar bekler, sonuçları dizi olarak verir (başarılı + hatalı). Hata olsa bile diğerlerini kaçırmazsın. Yeni (ES2020) metot.
// 3 endpoint'i dene, hangisi başarılı hangisi hatalı öğren
const sonuclar = await Promise.allSettled([
fetch("/api/a"),
fetch("/api/b"),
fetch("/api/c"),
]);
sonuclar.forEach((s) => {
if (s.status === "fulfilled") console.log("OK:", s.value);
else console.log("HATA:", s.reason);
});Hangisini ne zaman kullan?
| Metot | Davranış | Kullanım |
|---|---|---|
Promise.all | Hepsi başarılı → sonuçlar. Biri hata → reject | Bağımsız işler, hepsi gerekli |
Promise.race | İlk biten → onun sonucu | Timeout, en hızlı kaynak |
Promise.allSettled | Hepsi biter → hepsinin sonucu (başarı + hata) | Hata olsa bile hepsini istiyorum |
Mulakat SSS
JavaScript'te Promise nedir, en basit şekilde nasıl açıklanır?
Promise, henüz hazır olmayan ama ileride hazır olacak bir değeri temsil eden nesnedir. 'Söz' gibi: şimdi veremiyorum ama birazdan vereceğim. Üç durumu vardır: pending (bekliyor), fulfilled (başarılı, değer geldi), rejected (hata). Promise, JavaScript'te asenkron (eşzamansız) işleri düz ve okunabilir kodla yazmayı sağlar.
Promise'in üç durumu (state) nelerdir?
Pending: henüz tamamlanmamış, ne resolve ne reject olmuş. Fulfilled: başarıyla tamamlandı, bir değer var (resolve()). Rejected: hata oldu, bir hata mesajı var (reject()). Bir Promise yalnızca bir kez state değiştirebilir: pending → fulfilled VEYA pending → rejected. Sonra değişmez (immutable).
Promise ile callback arasındaki fark nedir?
Callback: bir fonksiyonu başka fonksiyona 'bitince bunu çağır' diye geçirirsin, iç içe geçtiğinde okunamaz (callback hell). Promise: asenkron sonucu bir nesne olarak temsil eder, .then().catch() ile düz zincir kurarsın. Promise, callback hell'i çözer ve hata yönetimini standartlaştırır.
Promise.all ve Promise.race farkı nedir?
Promise.all([p1, p2, p3]): hepsi başarılı olursa tüm sonuçları verir, biri bile hata verirse hemen reject olur. Promise.race([p1, p2, p3]): hangisi önce biterse onun sonucunu verir (ilk fulfilled veya ilk rejected). Tüm paralel işler için all, 'en hızlı olan kazansın' için race.
Promise zinciri (chaining) nasıl çalışır?
.then() her zaman yeni bir Promise döner. Bu sayede zincir kurabilirsin: onceA().then(onceB).then(onceC). Her .then() bir öncekinin sonucunu alır, dönüştürür, sonrakine geçirir. Hata olursa zincirin herhangi bir yerinde .catch() yakalar. Zincir, iç içe callback'lerin yerini alan düz (linear) bir yapıdır.
Mulakat sorusu: 'Promise.all bir elemani reddederse ne olur?'
Promise.all, bir eleman reject olursa hemen kendisi de reject olur (fail-fast). Diğer hâlâ devam eden Promise'lerin sonucu yine de gelir ama .then() çağrılmaz, sadece .catch() çalışır. Bu yüzden 'bağımsız işlerden biri bile başarısızsa tüm operasyon iptal' senaryolarında Promise.all idealdir.
Bir cümlede özet
Promise, "henüz hazır olmayan ama ileride hazır olacak değer" nesnesidir. Üç durumu vardır (pending/fulfilled/rejected), .then().catch().finally() ile sonucu alırsın, callback hell'den kurtarır, paralel işler için Promise.all/race/allSettled sunar.
Modern projelerde Promise, async/await'in temeli. fetch, axios, dosya işlemleri, veritabanı sorguları — hepsi Promise tabanlı. Bu dört yazıyı (closure, hoisting, Promise, async/await) bir oturuşta oku — JavaScript mülakatlarının %80'ini geçersin.
İlgili Yazılar
Promise öğrendin, dörtlü tamam
JavaScript'in en çok sorulan 4 mülakat konusunu (closure, hoisting, Promise, async/await) tamamladın. Sıradaki: this, prototype, event loop.