Neden Angular Şablonlarında Metot Kullanmamalıyız?
Merhaba bu yazımda, Angular şablonlarında metot kullanımın performansa etkisi hakkında bilgi vermeye çalışacağım.
Bu yazıyı Ng Turkey ekibinden Mehmet Erim’in yapmış olduğu Angular Zor Değil: Syntax canlı yayınını izledikten sonra yazmaya karar verdim. Sunum sırasında Mehmet Erim’in “Interpolation işlemlerinde metot çağrısının tercih edilmemesi” yönünde bir önerisi olmuştu. Sunum sonunda sorulan aynı soruya gerekli açıklamayı da yapmıştı. Bir örnekle Mehmet’in cevabını göstermek istedim.
Sorunun cevabını en başta vereyim . Angular şablonlarında metot çağrıları yapmak, büyük projelerde performans sorununa yol açabilir.
Şablonlar; Angular’ın en güçlü özelliklerinden biridir. Sunmuş olduğu built-in fonksiyonlar sayesinde DOM’daki işlemleri kolayca yapabilmeye olanak sağlıyor. Konuyla ilgili olarak detaylı bilgi için Angular Resmi Dokümanına bakabilirsiniz.
Geliştirme esnasında Html sayfasında bazı değerleri göstermek için karmaşık hesaplamaların yapılması kaçınılmazdır. Bunun için Component tarafında metotlar hazırlayıp, Html sayfasından doğrudan fonskyonu çağırarak dönen değeri ekranda gösterilir. Zaman zaman bir çok geliştiricinin(Ben de dahil) önemsemediği bu durum, uygulama büyüdükçe performans konusunda sıkıntılar yaratabilir. Eğer bu fonksiyonun içerisinde servis çağrısı yada büyük logic var ise ciddi performans sorunları kaçınılmaz olacaktır. Örnekle açıklamak gerekirse(Saçma bir örnek idare edin :) ) :
En son eklenen dizi ve Dizilerin listelendiği bölüm Html sayfasında Metot gösterilmektedir. Uygulama açıldığında Metot çalışarak bilgiler ekranda göstermektedir. Buraya kadar her şey normal(getter ve metot uygulama açılırken 2 kez tetiklendi. Yani log’a 4 kayıt atıldı. Bu durum normal değil ama şimdilik görmezden gelelim). Kullanıcı text alana yeni bir bilgi eklemek istediğinde yazmış olduğu harf sayısının 2 katı kadar getter ve metot tekrardan çalışmaktadır. Ekle butonuna basınca getter ve metot 2 kere daha tetiklenmektedir. Demo: Stackblitz
Uygulamanın kodu:
Html sayfasında 14. satırda getdiziler()
metodu kullanılarak ilgili bilgileri ekran da gösteriliyor.
Neden metot HTML’de birden fazla tetikleniyor?
Bu durum Angular’ın sunmuş olduğu Change Detection’den kaynaklamaktadır. Sayfa üzerinde, kullanıcının yapmış olduğu her bir işlemden sonra Angular sayfadaki değişiklikleri kontrol eder ve eğer değişiklik varsa DOM’da bu değişikliği gösterir. Detaylı bilgi için Emre Hızlı’nin Angular ChangeDetection Nedir? yazısına bakabilirsiniz.
Angular sayfadaki değişiklikleri kontrol ederken fonksiyonun değerinin değişip değişmediğini bilmez. Sayfanın güncel halini göstermek için, yapılan her bir kontrol esnasında getter ve metotlar tetiklenir. Örneğin Change Detection 100 kere çalışırsa getter ve metotlar da 100 kere çalışacaktır. Eğer sayfada çok fazla getter ve metot çağrıları yapılmış ise ciddi performans sorunları ortaya çıkacaktır.
Çözüm
1. Change Detection Stratejini (CDS) değiştirmek
Angular, Varsayılanı olarak Default
olmak üzere 2 tane CDS sunmaktadır. Örnekteki sorunu çözmek için CDS’yi default’tan, onPush
şeklinde değiştirebiliriz. onPush sadece ana component için çalışır, Child componentler için doğrudan çalışmaz. Child componentlere ait @Input
’ların referanslar değişmesi, ana component veya child componente bulunan event
’in tetiklenmesi, şablonlarda async
pipe ile kullanılan observerlardan yeni bir değerin emit edilesi ve ChangeDetectorRef
’in manuel tetiklensi durumunda Change Detection devreye girer.
@Input
’larda
onPush
stratejisini kullanılması durumunda son şekilde olacaktır: Bir önceki duruma göre, metot tetiklenmesi yarı yarıya düştü. Demo: StackBlitz
Uygulamanın Kodu :
Compenent’e ait kodda 7.satırdaki changeDetection: ChangeDetectionStrategy.OnPush
ekleme yapıldı. Kodun diğer kısımlar bir önceki örnekle birebir aynı.
2. Pure Pipe Kullanmak:
Html kodunda metot yerine pure pipe kullanmak ciddi bir artışı sağlayacaktır. Angular’ın dokümanına göre, Pipe’in giriş değeri değişir ise CDS devreye girecektir. Pipe’lar hakkında bilgi için Sevilay Sarar’ın Angular Pipe Nedir? Custom Pipe Nasıl Yapılır? yazısına bakabilirsiniz
Pure Pipe
ve onPush
CDS kullanılması durumunda son durum şu şekilde olacaktır: Log’da “Pipe Tetiklendi” uyarısı uygulama açıldığında ve ekle butonuna basıldığında görüntülenmektedir. Bunun anlamı: Pipe’in değeri değişmedikçe CDS pipe için devreye girmiyor. Demo: StackBlitz
Uygulamanın Kodu :
Uygulamaya Pipe eklendi ve Html sayfasında 4. satırdaki değişiklikler yapıldı.
Kapanış
Şablonlarda Interpolation işlemlerinde metot kullanmak yerine pipe kullanılması ciddi performans kazanımı sağlayacaktır.
Ek bilgi:
Aşağıdaki kullanım şekilleri de işe yarayacaktır.
Getter / Setter Kullanmak
Getter’da da, metotta olduğu gibi aynı durum yaşanmaktadır. Ama Setter ile değişkenin değeri değiştiği ve getter sadece değişen değeri döneceği için performansta sıkıntı yaratmayabilir.
@Input’larda async pipe kullanmak
Observable’dan yeni bir değer emit ediliği zaman, async pipe compenente değişikliklerin için kontrol edilmesini söyler ve CDS devre girer.
İlginizi Çekebilir
Sizin bu durumlar için kullandığınız yöntemler varsa paylaşırsanız sevinirim
Bir sonraki yazıda görüşmek üzere.