[Çeviri] Süper sezgisel etkileşimli diyagramlar ile RxJs sıralı dizileri birleştirmeyi öğrenin

Bu makale Max Koretskyi aka Wizard tarafından yazılan “Learn to combine RxJs sequences with super intuitive interactive diagrams” makalesinin çevirisidir.

0 1,535

Bu makale Max Koretskyi aka Wizard tarafından yazılan “Learn to combine RxJs sequences with super intuitive interactive diagrams” makalesinin Türkçe çevirisidir. Makaleyi orijinal dilinde okumak için aşağıdaki linki tıklayabilirsiniz.

Seqeunce’yi sıralı dizi olarak çevirdim. Observable, stream gibi kelimeleri çevirmedim. Bazı yerlerde parantez için türkçe karşılığını yazdım. Yazının içinde sıkça geçen bu iki kavram hakkında ön bir bilgi vermek gerekir diye düşünüyorum.

Stream: Verilerin bütün olarak değilde küçük parçalar halinde transfer etmeyi sağlayan bir yapıdır.

Observable: Herhangi bir streame abone olur ve sürekli dinler. Dinlenen stream içerisinde herhangi bir yayılım olursa önceden tanımlanan işlemleri uygular. Bu işleme Stream Subscription denmektedir

Başlıyoruz….


Yeterince karmaşık bir uygulama üzerinde çalışırken, genellikle birden fazla veri kaynağından gelen veriler vardır. Bu kaynaklar genellikle bir kaç dış veri noktası, örneğin Firebase veya kullanıcının arayüz bileşenleri ile olan etkileşimi olabilir. Sıralı dizi(seqeunce) birleştirme; birden çok veri kaynağı arasından gelen, ilişkili akışları(stream) tek bir streamde birleştirip, karışık sorgular yaratmamızı sağlayan bir tekniktir. Rxjs, bize bu işlemleri yaparken yardımcı olmak için çok çeşitli operatörler sunmaktadır. Bu makalede, en çok kullanılanlara göz atacağız.

Tüm operatörler arasındaki sezgisel akış diyagramlarını hazırlarken, yarı zamanlı animasyon uzmanı oldum diyebilirim. Diyagramlar hareketli gif olarak hazırlandığından yüklenmeleri biraz zaman alabilir. Lütfen sabırlı olun.

Örnek olarak hazırladığım kodda, lettable(yeni sürümle birlikte pipeable oldu.) operatörleri kullanacağım, eğer bu konu hakkında bilginiz yoksa buraya bakabilirsiniz. Ayrıca subscription(abonelik) ile eş zamanlı olarak teslim edilen ilk öğe ile eş zamansız( asynchronously) değerler streami üreten özel bir stream opeatörü kullandım.

ag-Grid’de yazılımcı avukatı olarak çalışıyorum. Eğer data-gridler konusunda meraklı iseniz veya en üst düzey Angular data grid için çözümler arıyorsanız “Get started with Angular grid in 5 minutes”’ rehberini bir deneyin. Sorularınızı cevaplamaktan mutluluk duyarım. Ve beni takip edin ve irtibatı koparmayalım.

Makale boyunca kullandığım grafiklerde kullanılan işaretler şunlardır.


Birden çok sıralı diziyi(sequence) aynı anda birleştirme

merge operatörü bakacağımız ilk operatördür. Bu operatör, birden çok observables streams’i birleştirir ve girdi olarak verilen her bir streamden gelen değerleri yayar(emit). Bir araya getirilen sıralı dizisinden(seqeunce) üretilen değerler, elde edilen bir sıralı dizinin parçası olarak yayılır. Bu işlem genellikle belgelerde düzleştirme işlemi olarak adlandırılır.

Girdi olarak verilen tüm streamler tamamlandıktan sonra elde edilen stream de tamamlanmış olur ve streamlerin biri hata fırlatırsa, elde edilen stream de hata fırlatacaktır. Eğer girdi olarak verilen herhangi bir stream tamamlanmazsa elde edilen stream de hiçbir zaman tamamlanmayacaktır.

Eğer streamlerin sırası ile ilgilenmiyor ve birleştirilmiş tüm streamlerle sanki tek streamden üretiliyormuş gibi ilgileniyorsanız bu operatörü kullanın.

Aşağıdaki diyagram; merge operatörünün, her biri 3 öğe üreten A ve B streamlerini birleştirip, değerlerin ortaya çıkış sırasına göre düşen değerlerini gösteriyor.

Yukarıdaki diagramda anlatılan kurgu için örnek kod şu şekildedir:

 

Ve Stackblitz’deki düzenlenebilir demo: https://stackblitz.com/edit/combining-sequences-merge

Birden çok sıralı diziyi(sequence) sırayla birleştirme

Bir sonraki bileştirme methodu concat. Girdi olarak verilen streamleri; tek seferde bir tane aktif subscription(abonelik) olacak şekilde, abone yaparak (subscribing) ve bu streamlerden gelen verileri yayarak birleştirir. Mevcut stream tamamlandıktan sonra bir sonraki stream’e abone olur ve değeri sıralı sonuc dizisine (sequence) geçer.

Eğer girdi olarak verilen tüm streamler tamamlanırsa, elde edilen stream tamamlanmış olur; Eğer girdi olarak verilen streamlerden bir tanesi hata verirse, elde edilen stream de hata fırlatır ve işleme devam etmez. Girdi olarak verilen streamlerden bir tanesi sonuçlanmazsa, elde edilen streamde hiç bir zaman sonuçlanmaz, bu aynı zamanda bazı streamler hiç bir zaman abone olmayacak(subscribed) demektir

Eğer streamların sırası sizin önemli ve concat operatörüne ilk geçtiğiniz stream’e ait değerleri ilk görmek istiyorsanız, concat operatörünü kullanın. Örneğin; elinizde değerleri bir önbellekten (cache) dağıtan gözlemlenebilir bir sıralı diziniz(observable sequences) ve değerleri uzaktaki bir sunucudan dağıtan başka bir sıralı diziniz(sequences) olsun. Eğer gelen değerlerin ilk olarak önbellekten dağıtılan değerler olduğunu garantiye alarak birleştirmek istiyorsanızconcat kullanın.

Aşağıdaki diyagram;concat operatörünün, Her biri 3 öğe üreten A ve B streamlerini birleştirip, ilk olarak A streaminden daha sonra B streaminden elde edilen sıraya göre düşen değerlerini gösteriyor.

Yukarıdaki diagramda anlatılan kurgu için örnek kod şu şekildedir:

 

Ve Stackblitz’deki düzenlenebilir demo: https://stackblitz.com/edit/concat

Sıralı dizileri(sequence) belirsiz bir şekilde birleştirme

Oldukça ilginç bir konsept sunan bir sonraki operatör race. Sıralı dizileri (sequence) kendi başına birleştirmez ancak değerleri ilk üreten observable sequence’i seçmek için kullanılır. Sıralı dizilerden(sequence) biri değerleri yaymaya başlar başlamaz, diğer sıralı diziler abonelikten çıkarılır ve göz ardı edilir.

Girdi olarak verilen streamlerden, seçilen stream tamamlandıktan sonra elde edilen streamde tamamlanmış olur. Eğer seçilen streamde hata ortaya çıkarsa, elde edilen streamde hata fırlatır. Bu iç akış tamamlanmazsa, elde edilen stream de asla tamamlanmayacaktır.

Bu operatörün, şu şekilde kullanımı faydalı olabilir. Değerler üreten bir çok kaynağınız varsa ,örneğin farklı yerlerde bulunan sunucular gibi, ve ağ(network)’dan kaynaklı gecikme süresi tahmin edilemeyebilir ve önemli ölçüde değişken olabilir. Bu operatörü kullanarak aynı istek talebini birden çok veri kaynağına gönderebilirsiniz ve ilk gelen sonucu tüketebilirsiniz.

Aşağıdaki diyagramda; race operatörünün, her biri 3 öğe üreten A ve B streamlerini birleştirip ve A streami ilk olarak yayılmaya başladığından, yalnızca A’ya ait değerlerin yayıldığını görebilirsiniz.

Yukarıdaki diagramda anlatılan kurgu için örnek kod şu şekildedir:

 

Ve Stackblitz’deki düzenlenebilir demo:https://stackblitz.com/edit/combining-sequences-race-b-is-ignored

Bilinmeyen sayıdaki sıralı diziyi(sequence), üst seviye observable ile birleştirme

Yukarıda gösterdiğim operatörler, sayısı bilinen sıralı dizileri(sequence) birleştirmek için kullanılır. Ama tüm sıralı dizileri(sequence) önceden bilmiyor ve çalışma anında sıralı dizileri(sequence) tembel(lazily) bir şekilde birleştirmek istersek ne olacak? Aslında, eş zamansız kodlarla çalıştığımız zaman bu durum sıkça karşımıza çıkar. Bazı kaynaklar için bir ağ(network) çağrısı, orijinal isteğin dönen değeri tarafından belirlenen, bir takım başka taleplerle(request) sonuçlanabilir.

Rxjs’de yukarıda gördüğümüz operatörlerin sıralı dizilerinden(sequence), sıralı dizisi(sequence) alan çeşitli varyasyonlarına sahiptir. Bunlar üst seviye (higher-order) gözlemlenebilirler(observable) denir. Operatörler, bu tür observablelardan kaynaklanan yayılmaların sıralanmasını ve birinci bölümde gördüğümüz kurallara göre bunlarla çalışmasını bekler.

Bu tür operatörler, herhangi iç streamin hata üretmesi durumunda hata yayar ve yalnızca örnek( instance) operatör olarak kullanılır. Şimdi hepsine tek tek bakalım.

MergeAll

Bu operatör yayılan tüm iç streamleri birleştirir ve düz birleştirme ile aynı anda her bir streamden değerler üretir.

Aşağıdaki diyagramda; A ve B iç stremlerini üreten üst seviye H streamini görebilirsiniz. mergeAll operatörü bu iki streamden gelen değerleri birleştirir ve daha sonra sonuç olarak sıralı dizeye( sequence) geçer.

Yukarıdaki diagramda anlatılan kurgu için örnek kod şu şekildedir:

 

Ve Stackblitz’deki düzenlenebilir demo:https://stackblitz.com/edit/merge-all

ConcatAll

Bu operatör yayılan tüm iç streamları birleştirir ve düz concat sıralı olarak her streamden değerler üretir

Aşağıdaki diyagramda; A ve B iç stremlerini üreten üst seviye H streamini görebilirsiniz. concatAll operatörü; ilk olarak A streaminden daha sonra B’den değerleri alır ve elde edilen sıralı dizinden( sequence) geçirir.

Yukarıdaki diagramda anlatılan kurgu için örnek kod şu şekildedir:

 

Ve Stackblitz’deki düzenlenebilir demo:https://stackblitz.com/edit/concat-all

SwitchAll

Bazen tüm iç streamlerden değerler almak ihtiyacımız olan şey değildir. Bazı senaryolarda; sadece en yeni iç sıralı diziden(sequence) gelen değerlerle ilgilenebiliriz. Bu fonksiyon için iyi bir örnek, arama işlemidir. Bir kullanıcı bazı metinleri yazarken, sunuculara istek gönderilir ve işlem eş zamansız olduğu için sonuç observable olarak döndürülür. Sonuç dönmeden önce kullanıcı arama kutusundaki metni güncellerse ne olur? İkinci talep gönderilir. Şimdiye kadar sunucuya iki arama talebi gönderildi. Bununla birlikte ilk arama artık ilgilenmediğiz sonuçlar içerir. Ayrıca, ilk aramanın sonucu ikinci aramanın sonucuyla birleştirildiyse, kullanıcı çok şaşırır. switchAll operatörünün sahneye çıktığı yer burası. Abone olur ve en son iç sıralı diziden(sequence) gelen değerleri alır ve bir önceki streamleri göz ardı eder.

Aşağıdaki diyagramda; A ve B iç stremlerini üreten üst seviye H streamini görebilirsiniz. concatAll operatörü; ilk olarak A streaminden daha sonra B’den değerleri alır ve elde edilen sıralı dizinden(sequence) geçirir.

Yukarıdaki diagramda anlatılan kurgu için örnek kod şu şekildedir:

 

Ve Stackblitz’deki düzenlenebilir demo: https://stackblitz.com/edit/switch-all

concatMap, mergeMap ve switchMap

İlginçtir ki concatMapmergeMap ve switchMap operatörleri; muadilleri olan, observable straemlerini çalıştıran concatAllmergeAll ve switchAll operatörlerinden daha sık kullanılır. Yine de, eğer düşünürseniz, neredeyse aynı şeylerdir. Tüm *map operatörleri iki bölümden oluşur. — mapping ile observable stream üretmek ve üst seviye observablelar tarafından üretilen iç streamlere kombinasyon mantığı uygulamak.

mergeAll operatörünün nasıl çalıştığını gösteren, aşağıdaki aşina olduğunuz koda bir göz atalım:

 

Burada map operatörü observables streami üretir ve mergeAll operatörü ise bu observablelardan gelen değerleri birleştirir ve bu yüzden map ve margerAll kolaylıkla mergeMap ile şu şekilde değiştirilebilir:

Sonuç tam olarak aynı olacak. Aynısı concatMap ve switchMap içinde geçerlidir. — Kendi başınıza denebilirsiniz.

Sıralı Dizilerin(sequences), değerlerini eşleştirerek birleştirilmesi

Önceki operatörler çoklu sıralı dizileri (sequence) düzleştirmemize ve sanki hepsi tek bir sıralı diziden geliyormuş gibi, elde edilen stream boyunca değişmeyen bu sıralı dizilerden (sequence) değerler sunmamıza izin verir. Bir sonraki bakacağımız operatörler kümesi, yine birden çok sıralı diziyi (sequence) girdi olarak alır, ancak elde edilen sıralı dizisine (sequence) tek bir birleşik değer üretmek için, her sıralı diziden (sequence) üretilen değerleri eşleştirmeleri bakımından farklılık gösterir.

Her bir operatör; son parametre ve isteğe bağlı olarak, ortaya çıkan bu sıralı dizilerin (sequence) nasıl birleştirileceğini tanımlayan bir tane sözde öngörü fonksiyonu alabilir. Bir çok örneklerimde, değerleri basitçe birleştiren ve ayırıcı olarak virgülü kulanan bir öngörü fonksiyonunu varsayılan şeklinde kullandım. Bölümün sonunda, özel bir öngörü fonksiyonun nasıl sağlanacağını göstereceğim.

CombineLatest

combineLatest gözden geçireceğimiz ilk operatör. Bu operatör, girdi olarak verilen sıralı dizilerinden(sequence), en son değeri almanıza ve elde edilen sıralı dizi için bunları bir değere dönüştürmenize imkan sağlar. RxJ’ler girdi olarak verilen her sıralı dizi(sequence) için son değeri önbelleğe alır ve tüm sıralı diziler(sequence) en az bir değer ürettiğinde, önbellekten en son değerleri alan öngörü fonksiyonunu kullanarak elde edilen bir değeri hesaplar, daha sonra sonuç streaminin hesaplama çıktısını yayar.

Ortaya çıkan stream, tüm iç streamler tamamlandığında, ortaya çıkean stream tamamlanır ve iç straemlerden herhangi biri bir hata fırlatırsa, ortaya çıkan stream bir hata fırlatır. İç streamlerden herhangi biri tamamlanmazsa ortaya çıkan stream asla tamamlanmayacaktır.

Öte yandan, herhangi bir stream değer yaymadan tamamlanırsa, sonuçta elde edilen stream aynı anda herhangi bir şey yaymadan tamamlanır, çünkü tamamlanan girdi olarak verilen streamden elde edilen değeri sonuç sıralı dizisine (sequence) dahil etmek artık imkansızdır. Ayrıca, bazı girdi olarak verilen streamlerden herhangi bir değer yaymaz ve hiçbir zaman tamamlanmazsa; combineLatestda asla yaymaz ve asla bitmez çünkü yine tüm streamlerin bir değer yaymasını bekler.

Mevcut durumdan bir kısmı değiştiğinde, güncel tutulması gereken bir durum kombinasyonunu değerlendirmeniz gerekirse, bu operatör faydalı olabilir. Basit bir örnek olarak bir izleme sistemi olabilir. Her servis, söz konusu servisin kullanılabilirliğini gösteren bir Boolean değer döndüren bir sıralı diziyle temsil edilir. Tüm servisler mevcutsa, izleme durumu yeşildir, bu nedenle öngörü fonksiyonu sadece mantıksal bir AND gerçekleştirmelidir.

Aşağıdaki diyagramda; A ve B stremlerini birleştiren combineLatest operatörünü görebilirsiniz. Tüm streamler en az bir değer yaydığı anda, her yeni yayılım sonuç streami boyunca birleştirilmiş bir değer üretir:

Yukarıdaki diagramda anlatılan kurgu için örnek kod şu şekildedir:

Ve Stackblitz’deki düzenlenebilir demo: https://stackblitz.com/edit/combine-latest


Zip

Bu operatör, bir şekilde bir fermuarın kıyafet veya çanta üzerindeki mekaniğini andıran bir başka ilginç birleştirme özelliğidir. Bir tuple (girdi olarak verilen bir çift stream durumunda) olarak karşılık gelen değerlerin iki veya daha fazla sıralı dizisini(sequence) bir araya getirir.Tüm girdi olarak verilen streamlerden, karşılıklı değerin yayılmasını bekler daha sonra öngörü fonksiyonunu kullanarak bunları tek bir değere dönüştürür ve sonucu yayar. Her kaynak sıralı dizisinden (sequence) yeni bir çift değer aldığında yayınlayacaktır, dolayısıyla kaynak sıralı dizilerinden biri değerleri, diğer sıralı diziden daha hızlı yayınlarsa, yayınlama oranı, sıralı iki dizinin yavaşlamasıyla belirlenir.

Ortaya çıkan stream, iç streamlerden herhangi biri tamamlandığında tamamlanır ve karşılık gelen eşleşen çiftler diğer streamlerden yayılır. İç streamlerden herhangi biri tamamlanmazsa, ortaya çıkan akış asla tamamlanmayacaktır ve iç akışlardan herhangi biri hata verirse ortaya çıkan stream de bir hata fırlatır

Bu operatörü, aralıklı bir değer aralığı üreten bir streame uygulamak için rahatlıkla kullanılabilir. Aralık(range) streaminden gelen değerleri dönen öngörü fonksiyonu için basit bir örnek:

 

Aşağıdaki diyagramda; A ve B streamlerini birleştiren zip operatörünü görebilirsiniz. Karşılıklı bir çift eşleştiğinde, elde edilen sıralı dizi (sequence) birleştirilmiş bir değer üretir.

Yukarıdaki diagramda anlatılan kurgu için örnek kod şu şekildedir:

 

Ve Stackblitz’deki düzenlenebilir demo: https://stackblitz.com/edit/zip

forkJoin

Bazen sadece her birinin son yayılan değeri ile ilgilendiğiniz bir grup streaminiz olabilir. Genellikle bu tür sıralı diziler sadece tek bir yayılıma sahiptir. Örneğin, birden çok ağ isteği yaparak, sadece hepsinden bir yanıt alındığınızda işlem yapmak isteyebilirsiniz. Bir şekilde Promise.all işlevselliğine benzer. Ancak, birden fazla öğe yayan bir streame sahipseniz, son değer dışındaki diğer tüm değerler göz ardı edilir.

Ortaya çıkan stream, tüm iç streamlerin tümü tamamlandığında yalnızca bir kez yayılır. İç streamlerden herhangi biri tamamlanmazsa, ortaya çıkan stream de asla tamamlanmayacaktır ve iç streamlerden herhangi biri hata verirse, ortaya çıkan stream de hata fırlatır.

Aşağıdaki diyagramda; A ve B streamlerini birleştiren forkJoin operatörünü görebilirsiniz. Son karşılıklı çift eşleştiğinde, elde edilmiş sıralı dizi (sequence) birleştirilmiş bir değer üretir:

Yukarıdaki diagramda anlatılan kurgu için örnek kod şu şekildedir:

 

Ve Stackblitz’deki düzenlenebilir demo: https://stackblitz.com/edit/fork-join

WithLatestFrom

withLatestFrom, bu yazıda son olarak göz atacağımız operatördür. Bu operatör bir rehber streaminiz olduğunda kullanılır ancak diğer streamlerden gelen son değerlere de ihtiyaç duyar. Bir benzeri olan combineLatest operatörü, girdi olarak verilen herhangi bir streamden yayılım olduğunda, yeni bir değer yayar. withLatestFrom ise rehber streamden bir yayılım olursa bey bir değer yayar. combineLatestde olduğu gibi; her hangi bir streamden yayılan en az bir değer beklemektedir ve rehber stream tamamlandığında, tek bir yayılım olmadan tamamlanabilir. Rehberlik yapan stream tamamlanmazsa asla ortaya çıkan stream tamamlanmayacaktır ve iç streamlerden herhangi biri hata verirse, ortaya çıkan stream hata hata fırlatır.

Aşağıdaki diyagramda; A ve B streamlerini B’nin rehberliğinde birleştiren withLatestFrom operatörünü görebilirsiniz. Ne zaman Rehberlik yapan B streaminden yeni bir değer yayılırsa , sonuç sıralı dizisi (sequence) A streaminden gelen en son değerle birleştirilmiş bir değer üretir:

Yukarıdaki diagramda anlatılan kurgun için örnek kod şu şekildedir:

Ve Stackblitz’deki düzenlenebilir demo: https://stackblitz.com/edit/with-latest-from

Öngörü Fonskiyonu (Projection function)

Bölümün başında da bahsedilen, değerleri eşleştirerek birleştiren, tüm operatörler isteğe bağlı bir öngörü fonksiyonu alır. Bu fonksiyon sonuç değerinin dönüşümünü tanımlar. Bu fonksiyonu kullanarak, yalnızca belirli bir girdi olarak verilen sıralı dizinden (sequence) bir değer yayınlamayı veya istediğiniz şekilde değerleri birleştirmeyi seçebilirsiniz:

Eğer tüm diyagramları tek bir yerde görmek isterseniz , Pierre Criulanscy tarafından hazırlanlanan gist’e bakabilirsiniz.

Okuduğunuz için teşekkürler! Bu makaleyi beğendiyseniz, aşağıdaki alkış butonuna 👏 basın. Bu benim için çok şey ifade ediyor ve diğer insanların hikayeyi görmesine yardımcı oluyor.

Daha fazla bilgi için beni Twitter ve Medium’da takip edin.

Email adresiniz yayınlanmayacaktır.