Angularda Promise ve Observable
Mustafa Seker
Last updated
Mustafa Seker
Last updated
Angularda asekron (async) programalada önemli bir rol alan Observable ve Promise yapılarından bahsedeceğim.
Öncelikle nedir bu asenkron programlama
Kullanmakta olduğumuz programlarda aynı anda birden çok işlem yapılabilmektedir. Örneğin siz kullanıcı arayüzünde bir yazı görüyorken arka planda bir web servisine istek gönderilmiş ve cevabı bekleniyor olabilir. İlk nesil programlarda web servisinden cevap gelene kadar siz kullanıcı arayüzünde herhangi bir tuşa basamazdınız. Eğer basarsanız bir şey olmayacaktır ve peş peşe bir kaç defa basarsanız program durduruldu hatası alırdık.
Asenkron fonksiyon tanımlamak özellikler farklı tipte işlemleri bir arada yürütüyorken kullanmak oldukça pratik ve sağlıklıdır. Ancak her fonksiyonu Asenkron olarak yazılmaz. Dataların kontrolünü kaybedebilirsiniz.
Kısacası asenkron programlama programın senkron bir şekilde değil de öncelik verdiğimiz işlemlerin daha önce yapılmasını sağlayan ya da sağladığımız programlama türüdür.
Bu durumda Promise ve Observable hangi amaçla kullanıyoruz şimdi onlara gelelim.
Angular’da Promise, JavaScript’in asenkron programlama modelini kullanmanıza olanak tanıyan bir yapıdır. Bir Promise, bir işlemin tamamlanması veya bir sonuç üretmesi için bir süre beklemek üzere oluşturulan bir nesnedir.
Bir Promise, genellikle ağ istekleri, dosya okuma/yazma gibi işlemler veya zamanlayıcılar gibi asenkron operasyonlar için kullanılır. İşlem tamamlandığında Promise, sonucu temsil eden bir değerle tamamlanır veya hata durumunda bir hata nesnesiyle reddedilir.
Angular’da, Promise’lar, özellikle eski kod tabanları veya dışa bağımlılıklarla çalışırken kullanışlı olabilir. Ancak, Angular 2 ve sonraki sürümlerde Promise’lar yerine Observable’lar genellikle tercih edilir. Observable’lar, daha kapsamlı bir şekilde asenkron programlama için kullanılır ve daha fazla esneklik sağlar.
Promise’lar, Angular’da çeşitli senaryolarda kullanılabilir. Örneğin, bir HTTP isteği yaparken veya bir bileşenin başka bir bileşenden veri almasını beklerken bir Promise kullanabilirsiniz. Promise’lar, bir dizi ardışık veya paralel işlemi zincirleme ve yönetme yeteneği sağlar.
Promise nesnesindeki diğer bazı fonksiyonlar şunlardır:
Promise.resolve(): Belirtilen değeri hemen tamamlanmış bir Promise ile çözer.
Promise.reject(): Belirtilen nedenle reddedilmiş bir Promise oluşturur.
Promise.allSettled(): Birden çok Promise nesnesini birleştirir ve tümünün tamamlandığında sonuçları döndürür. Reddedilen ve çözümlenen Promise’lerin sonuçlarını içeren bir dizi döndürür.
Promise.any(): Birden çok Promise nesnesini yarıştırır ve en az biri çözümlendiğinde veya hepsi reddedildiğinde sonucu döndürür. İlk çözümlenen Promise’in sonucunu döndürür.
Bu fonksiyonlar, Promise yapısını daha fazla kontrol ve esneklik sağlamak için kullanılır. Promise.resolve() ve Promise.reject() ile anında tamamlanan veya reddedilen Promise’ler oluşturabilir, Promise.allSettled() ile tüm Promise’lerin sonuçlarını toplayabilir ve Promise.any() ile en hızlı tamamlananın sonucunu elde edebilirsiniz.
Peki bu fonksiyonların dönüşleri sonrasında kullanbilceğimiz fonksiyonlar nelerdir inceleyelim.
then(): Bir Promise nesnesinin tamamlandığında veya çözümlendiğinde çalışacak olan bir geri çağırma fonksiyonunu belirtmek için kullanılır.
catch(): Bir Promise nesnesinin reddedildiğinde çalışacak olan bir hata yönetimi geri çağırma fonksiyonunu belirtmek için kullanılır.
finally(): Bir Promise nesnesinin tamamlandığında, çözümlendiğinde veya reddedildiğinde her durumda çalışacak olan bir geri çağırma fonksiyonunu belirtmek için kullanılır.
Bunları daha iyi anlamamız için aşağıdaki kod bloklarını inceleyelim.
Örneğin, aşağıdaki örnek, getUser() fonksiyonunu kullanarak kullanıcı bilgilerini bir Promise içinde döndürür:
Bu durumda, getUser() fonksiyonu bir kullanıcı nesnesini içeren bir Promise döndürür. Bu Promise hemen tamamlanmıştır ve kullanıcı nesnesi doğrudan then() veya await kullanılarak alınabilir:
Bu şekilde, Promise.resolve() kullanarak anında tamamlanmış bir Promise döndürerek, bir işlemin sonucunu hızlıca elde etmek mümkün olur.
Burada gördüğünz gibi then() ifadesi Promise ana yapısından sonra dönecek olan nesne üzerinde etkisi olan bir yapıdır. Aşağıdaki kod bloklarında da onu inceleyelim.
then(): Bir Promise nesnesi tamamlandığında veya çözümlendiğinde çalışacak olan bir geri çağırma fonksiyonunu belirtmek için kullanılır. then() zincirleme olarak kullanılabilir, böylece ardışık işlemleri gerçekleştirmek için birden fazla then() çağrısı yapılabilir.
myPromise aslında yukarıdaki örnekteki getUser() fonskisyonu gibi düşünebiliriz.
then() fonksiyonundan sonra ise aktif olarak kullanabileceğimiz iki yapı vardır.
Catch(): Bir Promise nesnesi reddedildiğinde çalışacak olan bir hata yönetimi geri çağırma fonksiyonunu belirtmek için kullanılır. catch() ile hata yakalanabilir ve uygun şekilde işlenebilir.
Finally(): Bir Promise nesnesi tamamlandığında, çözümlendiğinde veya reddedildiğinde her durumda çalışacak olan bir geri çağırma fonksiyonunu belirtmek için kullanılır. finally() bloğu, temizleme veya kaynakları serbest bırakma gibi işlemleri gerçekleştirmek için kullanılabilir.
Promise yapısı bu şekildeydi. Promise’in yerini daha çok Observable aldı. Şimdi Observable yapısını inceleyelim
Observable ise RxJS (Reactive Extensions for JavaScript) kütüphanesi tarafından sağlanan bir yapıdır. Observable, veri akışını temsil eder ve bu akış üzerinde çeşitli operasyonlar gerçekleştirilebilir. Observable’lar, birden çok değer döndürebilir ve zaman içinde değişebilir. Bu, gerçek zamanlı veri akışlarını ele almak için çok kullanışlıdır. Örneğin, kullanıcı etkileşimleri, WebSocket bağlantıları gibi sürekli güncellenen veri kaynakları ile çalışırken Observable’lar tercih edilir.
Angular, HTTP istekleri ve diğer asenkron işlemlerle çalışırken genellikle Observable’ları tercih eder. Bununla birlikte, Promiseleri de destekler ve gerektiğinde kullanılabilir. RxJS, Angular projelerinde yaygın olarak kullanılan bir kütüphanedir ve Observable’ları işlemek için zengin bir işlevsellik sunar.
Angular’da Observable nesneleriyle birlikte kullanabileceğiniz bazı yaygın fonksiyonlar şunlardır:
subscribe(): Bir Observable üzerindeki veri akışını dinlemek ve tepki vermek için kullanılır.
unsubscribe(): subscribe() işleminden sonra Observable’daki veri akışını durdurmak için kullanılır. Bellek sızıntılarını önlemek için önemlidir.
pipe(): Observable üzerinde işlem yapan operatörleri zincirleme şeklinde uygulamak için kullanılır.
retry(): Hata durumunda Observable’ın yeniden denemesini sağlamak için kullanılır.
Bunlar sadece bazı örneklerdir ve RxJS kütüphanesi birçok farklı operatör ve fonksiyon sunar.
Yukarıdaki fonskiyonlardan en önemlisi subscribe() dır. Bu fonksiyonun temel özellikleri nelerdir.
Angular’da Observable nesneleri, veri akışını temsil eder ve asenkron işlemleri yönetmek için kullanılır. subscribe() fonksiyonu, bir Observable üzerindeki veri akışını dinlemek ve ona tepki vermek için kullanılır.
subscribe() fonksiyonu, üç adet parametre alabilir: next, error ve complete. Bu parametreler, Observable tarafından gönderilen değerlere ve durumlara tepki vermek için kullanılır.
next: Observable tarafından gönderilen her bir değer için çağrılır. Bu değer, Observable tarafından yayınlanan veriyi temsil eder.
error: Eğer bir hata oluşursa çağrılır. Bu parametre, hatayı temsil eden bir nesne alır.
complete: Observable tamamlandığında çağrılır. Yani, Observable artık yeni değer yayınlamayacak duruma geldiğinde çağrılır.
Bir Observable üzerinde subscribe() işlemi gerçekleştirildiğinde, next fonksiyonu değerler için çağrılır, error fonksiyonu hata durumunda çağrılır ve complete fonksiyonu Observable tamamlandığında çağrılır.
İşte bir örnek:
Bu örnekte, Observable tarafından next() fonksiyonu aracılığıyla yayınlanan her bir değer subscribe() fonksiyonu içindeki next parametresi ile yakalanır. complete() fonksiyonu çağrıldığında ise complete parametresi çalışır ve “Observable tamamlandı” mesajı yazdırılır.
subscribe() fonksiyonu, Observable üzerindeki veri akışını dinlemek ve bu verilere uygun şekilde tepki vermek için kullanılır.
Observable ile ilgili son olarak fonksiyon dönüşünde kullanabileceğimiz yararlı ekstra fonksiyonları inceleyelim.
Map: Bir Observable üzerindeki değerleri dönüştürmek için kullanılır. Yeni bir Observable döndürür.
Filter: Bir Observable üzerindeki değerleri filtrelemek için kullanılır. Sadece belirli bir koşulu sağlayan değerleri yayınlar.
take: Belirli bir sayıda değeri yayınlamak için kullanılır. İstenilen sayıda değeri aldıktan sonra complete() işlemi gerçekleştirir.
merge: Birden çok Observable’ı birleştirmek için kullanılır. İç içe geçmiş subscribe() çağrıları yerine tek bir Observable döndürür.
concat: Birden çok Observable’ı ardışık olarak birleştirmek için kullanılır. İlk Observable tamamlandığında ikinci Observable başlar.
Observable ile ilgili konuşabileceğimiz konularda bu kadardı.
Observable ve Promise arasındaki benzerlikleri ve farklılıkalar göz atalım.
Benzerlikler:
Asenkron İşlemler: Hem Promise hem de Observable, asenkron işlemleri yönetmek için kullanılır. İkisi de asenkron olarak veri akışını temsil eder ve işlemlerin tamamlanması veya hata durumlarında tepki verirler.
İşlem Tamamlanması: Hem Promise hem de Observable, bir işlemin tamamlanması durumunda bir değer döndürebilir. Promise’lar, tek bir değeri temsil ederken, Observable’lar birden çok değeri temsil edebilir.
Zincirleme: Hem Promise hem de Observable, ardışık işlemleri zincirleme şeklinde gerçekleştirmek için kullanılabilir. Bu, bir işlem tamamlandığında veya bir değer döndüğünde bir sonraki işlemi tetikler.
Farklılıklar:
Birden Fazla Değer: Promise, yalnızca bir değeri temsil ederken, Observable birden çok değeri temsil edebilir. Observable, zaman içinde değişen ve sürekli güncellenen veri akışlarını ele almak için daha uygundur.
İşlem Kontrolü: Promise’lar, bir kez başlatıldıktan sonra tamamlanır ve sonucu veya hatayı döndürür. Tamamlandıktan sonra bir Promise’ın durumu değiştirilemez. Observable’lar ise işlem kontrolünü daha esnek bir şekilde sağlar. Yeni değerler yayınlayabilir, hatalar gönderebilir ve tamamlanabilirler. Ayrıca, bir Observable’ı abone olduğunuz sürece veri akışı devam eder.
İptal Edilebilirlik: Promise’lar, bir kez başladıktan sonra iptal edilemezler. Observable’lar ise aboneliği iptal etme yeteneğine sahiptir. Bu, gereksiz veri alımını önlemek ve bellek sızıntılarını önlemek için faydalı olabilir.
Operatörler: Observable’lar, RxJS gibi bir kütüphane tarafından desteklenir ve zengin bir operatör kümesi sunar. Bu operatörler, veri akışını dönüştürmek, filtrelemek, birleştirmek, gecikme eklemek gibi çeşitli işlemleri gerçekleştirmek için kullanılabilir. Promise’lar ise bu tür operatörlere doğrudan erişim sağlamaz.
Sonuç olarak, Promise’lar tek bir değeri temsil eden ve daha basit asenkron işlemleri yöneten yapılar iken, Observable’lar birden çok değeri temsil eden, sürekli güncellenen veri akışlarını ele alabilen ve daha fazla işlem kontrolü sağlayan yapılar olarak öne çıkar.