Bu ders için video bulunmamaktadır.
Ders İçeriği
Giriş: Callback Cehenneminden Kaçış
Önceki derste, eşzamansız işlemleri yönetmek için callback fonksiyonlarını öğrendik. Callback'ler basit senaryolarda işe yarasa da, birbirine bağlı birden fazla eşzamansız işlem gerçekleştirmemiz gerektiğinde kod hızla karmaşıklaşabilir ve okunması zorlaşabilir. İç içe geçmiş çok sayıda callback fonksiyonu, "Callback Hell" (Callback Cehennemi) veya "Pyramid of Doom" (Kıyamet Piramidi) olarak adlandırılan bir yapıya yol açabilir.
Bu tür kodları okumak, anlamak ve hata ayıklamak oldukça zordur. İşte bu noktada, ES6 (ECMAScript 2015) ile tanıtılan Promise (Söz) nesneleri devreye girer. Promise'lar, eşzamansız işlemleri ve onların sonuçlarını (başarı veya hata) temsil eden nesnelerdir ve callback cehennemine daha temiz, okunabilir ve yönetilebilir bir alternatif sunarlar.
Bu derste, Promise'ların ne olduğunu, nasıl çalıştıklarını, nasıl oluşturulduklarını ve eşzamansız kodumuzu nasıl iyileştirdiklerini öğreneceğiz.
Promise Nedir?
Bir Promise, henüz tamamlanmamış ancak gelecekte bir sonuç (değer veya hata) üretecek olan bir eşzamansız işlemin sonucunu temsil eden bir nesnedir. Bir nevi, "Sana söz veriyorum, bu işlem bittiğinde sana ya sonucu ya da neden başarısız olduğunu bildireceğim" diyen bir yapıdır.
Bir Promise şu üç durumdan birinde olabilir:
- Pending (Beklemede): Promise'ın başlangıç durumu. İşlem henüz tamamlanmamıştır (ne başarılı ne de başarısız).
- Fulfilled (Başarılı/Yerine Getirildi): İşlem başarıyla tamamlandı. Promise bir değere sahiptir (bu değere
resolve
edilen değer denir). - Rejected (Başarısız/Reddedildi): İşlem bir hata nedeniyle başarısız oldu. Promise bir hataya (sebebe) sahiptir (bu hataya
reject
edilen sebep denir).
Bir Promise, pending durumundan ya fulfilled ya da rejected durumuna geçer ve bu geçiş sadece bir kez olur. Bir Promise bir kez sonuçlandığında (settled olduğunda - yani fulfilled veya rejected olduğunda), durumu ve sonucu asla değişmez.
Promise Oluşturma
Bir Promise, new Promise(executor)
yapıcı (constructor) fonksiyonu ile oluşturulur. executor
, iki argüman alan bir fonksiyondur: resolve
ve reject
.
resolve(value)
: Eşzamansız işlem başarıyla tamamlandığında çağrılır.value
, işlemin sonucudur ve Promise'ı fulfilled durumuna geçirir.reject(reason)
: Eşzamansız işlem sırasında bir hata oluştuğunda çağrılır.reason
, hatanın sebebidir (genellikle bir Error nesnesi) ve Promise'ı rejected durumuna geçirir.
executor
fonksiyonu, Promise oluşturulduğunda hemen çalıştırılır ve genellikle eşzamansız işlemi başlatır.
Not: Genellikle kendi Promise'larımızı doğrudan oluşturmak yerine, fetch
gibi yerleşik API'lerin veya kütüphanelerin döndürdüğü Promise'ları kullanırız. Ancak Promise'ın nasıl çalıştığını anlamak için nasıl oluşturulduğunu bilmek önemlidir.
Promise Kullanımı: .then()
, .catch()
, .finally()
Bir Promise oluşturulduktan veya bir fonksiyondan alındıktan sonra, onun sonucunu (başarı veya hata) işlemek için özel metodlar kullanılır:
promise.then(onFulfilled, onRejected)
Bir Promise'ın sonucunu (settled olduğunda) işlemek için en temel metoddur. İki adet opsiyonel callback fonksiyonu alır:
onFulfilled(value)
: Promise başarılı (fulfilled) olduğunda çalıştırılır. Argüman olarak Promise'ınresolve
edilen değerini alır.onRejected(reason)
: Promise başarısız (rejected) olduğunda çalıştırılır. Argüman olarak Promise'ınreject
edilen sebebini (hata nesnesini) alır.
.then()
metodu yeni bir Promise döndürür. Bu, Promise'ları zincirlememizi (chaining) sağlar.
promise.catch(onRejected)
Sadece hataları (rejected durumunu) yakalamak için kullanılan bir kısayoldur. promise.then(null, onRejected)
ile eşdeğerdir.
Kodun okunabilirliğini artırır, çünkü başarı ve hata işleme mantığını ayırır.
promise.finally(onFinally)
Promise'ın sonucundan (başarılı veya başarısız) bağımsız olarak, Promise sonuçlandığında (settled olduğunda) her zaman çalıştırılacak bir callback fonksiyonu eklemek için kullanılır.
Genellikle temizleme işlemleri (örneğin, yükleniyor göstergesini kaldırmak, dosyayı kapatmak) için kullanılır.
onFinally
callback'i herhangi bir argüman almaz.
Promise Zincirleme (Chaining)
Promise'ların en güçlü özelliklerinden biri zincirlenebilmeleridir. .then()
, .catch()
ve .finally()
metodları her zaman yeni bir Promise döndürdüğü için, bu metodları ardışık olarak çağırarak bir dizi eşzamansız işlemi sırayla ve daha okunabilir bir şekilde yönetebiliriz.
Bir .then()
içindeki callback fonksiyonu:
- Bir değer döndürürse, zincirdeki bir sonraki
.then()
bu değeri alır. - Yeni bir Promise döndürürse, zincirdeki bir sonraki
.then()
bu yeni Promise'ın çözülmesini (resolve olmasını) bekler ve onun sonucunu alır. - Bir hata fırlatırsa (veya reject edilmiş bir Promise döndürürse), zincirdeki bir sonraki
.catch()
bloğu çalıştırılır.
Gördüğünüz gibi, Promise zincirleme, callback cehennemine göre çok daha düz, okunabilir ve yönetilebilir bir kod yapısı sunar.
Alıştırmalar
- 1 saniye sonra "Merhaba" mesajını resolve eden bir Promise oluşturun ve
.then()
ile bu mesajı konsola yazdırın. - 2 saniye sonra rastgele bir sayı üreten ve bu sayıyı resolve eden bir Promise oluşturun.
.then()
ile sayıyı alın ve çift mi tek mi olduğunu konsola yazdırın. - 1.5 saniye sonra %50 ihtimalle resolve eden (%50 ihtimalle "Başarılı!" mesajıyla), %50 ihtimalle reject eden (bir Error nesnesiyle) bir Promise oluşturun. Hem
.then()
hem de.catch()
kullanarak her iki durumu da ele alın. - Bir Promise zinciri oluşturun: İlk
.then()
bir sayıyı alsın ve 2 katını döndürsün. İkinci.then()
bu sonucu alsın, 10 eklesin ve sonucu konsola yazdırsın. Zincirin sonuna bir.catch()
ekleyerek olası hataları yakalayın. Promise.resolve(deger)
vePromise.reject(sebep)
statik metodlarını araştırın. Bunlar ne işe yarar ve nasıl kullanılır?
Bu derste, eşzamansız JavaScript kodunu yönetmek için callback'lere güçlü bir alternatif olan Promise'ları öğrendik:
- Promise: Gelecekteki bir işlemin sonucunu (başarı veya hata) temsil eden bir nesnedir.
- Durumlar: Pending (beklemede), Fulfilled (başarılı), Rejected (başarısız).
- Oluşturma:
new Promise((resolve, reject) => { ... })
ile yapılır.resolve
başarıyı,reject
hatayı bildirir. - Kullanım:
.then(onFulfilled, onRejected)
: Başarı ve/veya hata durumlarını işler..catch(onRejected)
: Sadece hataları işler..finally(onFinally)
: Sonuçtan bağımsız olarak her zaman çalışır.
- Zincirleme (Chaining):
.then()
,.catch()
,.finally()
metodlarının yeni Promise'lar döndürmesi sayesinde, eşzamansız işlemler ardışık ve okunabilir bir şekilde bağlanabilir. - Faydaları: Callback cehennemini önler, kod okunabilirliğini ve yönetilebilirliğini artırır, hata yönetimini kolaylaştırır.
Promise'lar, modern JavaScript'te eşzamansız programlamanın temel taşlarından biridir. Bir sonraki derste, Promise'lar üzerine inşa edilmiş ve eşzamansız kodu daha da senkron gibi yazmamızı sağlayan async/await
sözdizimini inceleyeceğiz.