Angular uygulamanızın performansını nasıl iyileştirebilirsiniz?
Yayınlanan: 2020-04-10En büyük ön uç çerçevelerinden bahsederken, Angular'dan bahsetmemek imkansız. Yine de, onu öğrenmek ve akıllıca kullanmak için programcılardan çok çaba gerektirir. Ne yazık ki, Angular konusunda deneyimli olmayan geliştiricilerin bazı özelliklerini verimsiz bir şekilde kullanma riski vardır.
Bir ön uç geliştirici olarak her zaman üzerinde çalışmanız gereken birçok şeyden biri, uygulamanın performansıdır. Geçmişteki projelerimin büyük bir kısmı, genişletilmeye ve geliştirilmeye devam eden büyük kurumsal uygulamalara odaklandı. Ön uç çerçeveleri burada son derece yararlı olacaktır, ancak bunları doğru ve makul bir şekilde kullanmak önemlidir.
Angular uygulamanızın performansını anında artırmanıza yardımcı olabilecek en popüler performans artırma stratejilerinin ve ipuçlarının hızlı bir listesini hazırladım. Lütfen buradaki tüm ipuçlarının sürüm 8'deki Angular için geçerli olduğunu unutmayın.
ChangeDetectionStrategy ve ChangeDetectorRef
Değişiklik Algılama (CD) , Angular'ın veri değişikliklerini algılama ve bunlara otomatik olarak tepki verme mekanizmasıdır. Standart uygulama durumu değişikliklerinin temel türlerini listeleyebiliriz:
- Olaylar
- HTTP İsteği
- zamanlayıcılar
Bunlar asenkron etkileşimlerdir. Soru şudur: Angular, bazı etkileşimlerin (tıklama, aralık, http isteği gibi) gerçekleştiğini ve uygulama durumunu güncellemeye ihtiyaç olduğunu nasıl bilebilir?
Cevap, temel olarak asenkron etkileşimleri izlemek için tasarlanmış karmaşık bir sistem olan ngZone'dur . Tüm işlemler ngZone tarafından kaydedilirse, Angular bazı değişikliklere ne zaman tepki vereceğini bilir. Ancak tam olarak neyin değiştiğini bilmiyor ve tüm bileşenleri birinci derinlikte kontrol eden Değişiklik Tespiti mekanizmasını başlatıyor.
Angular uygulamasındaki her bileşenin, Değişiklik Algılama başlatıldığında bu bileşenin nasıl davranması gerektiğini tanımlayan kendi Değişiklik Algılayıcısı vardır - örneğin, bir bileşenin DOM'sini yeniden oluşturma ihtiyacı varsa (bu oldukça pahalı bir işlemdir). Angular Change Detection'ı başlattığında, her bir bileşen kontrol edilecek ve görünümü (DOM) varsayılan olarak yeniden oluşturulabilecek.
Bunu ChangeDetectionStrategy.OnPush kullanarak önleyebiliriz:
@Bileşen({ seçici: 'foobar', templateUrl: './foobar.component.html', styleUrls: ['./foobar.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush })
Yukarıdaki örnek kodda da görebileceğiniz gibi, bileşenin dekoratörüne ek bir parametre eklememiz gerekiyor. Ancak bu yeni değişiklik algılama stratejisi gerçekten nasıl çalışıyor?
Strateji, Angular'a belirli bir bileşenin yalnızca @Inputs() öğesine bağlı olduğunu söyler. Ayrıca, @Inputs() bileşenlerinin tümü değişmez bir nesne gibi davranacaktır (örneğin, bir nesnenin @Input()'undaki yalnızca özelliği değiştirdiğimizde, referansı değiştirmeden bu bileşen kontrol edilmeyecektir). Bu, birçok gereksiz kontrolün atlanacağı ve uygulama performansımızı artırması gerektiği anlamına gelir.
ChangeDetectionStrategy.OnPush içeren bir bileşen yalnızca aşağıdaki durumlarda kontrol edilecektir:
- @Input() referansı değişecek
- Bileşenin şablonunda veya alt öğelerinden birinde bir olay tetiklenir
- Bileşende gözlemlenebilir bir olay tetikleyecektir
- CD , ChangeDetectorRef hizmeti kullanılarak manuel olarak çalıştırılacaktır.
- görünümde zaman uyumsuz boru kullanılır (zaman uyumsuz boru, değişiklikler için kontrol edilecek bileşeni işaretler - kaynak akışı yeni bir değer yayınladığında bu bileşen kontrol edilir)
Yukarıdakilerin hiçbiri olmazsa, belirli bir bileşen içinde ChangeDetectionStrategy.OnPush kullanılması, bileşenin ve tüm iç içe geçmiş bileşenlerin CD başlatıldıktan sonra kontrol edilmemesine neden olur.
Neyse ki, ChangeDetectorRef hizmetini kullanarak veri değişikliklerine tepki verme konusunda tam kontrole sahip olabiliriz. Zaman aşımlarımız, isteklerimiz, abonelik geri aramalarımız içinde ChangeDetectionStrategy.OnPush ile gerçekten buna ihtiyacımız olursa CD'yi manuel olarak başlatmamız gerektiğini hatırlamalıyız:
sayaç = 0; yapıcı(özel changeDetectorRef: ChangeDetectorRef) {} ngOnInit() { setTimeout(() => { this.counter += 1000; this.changeDetectorRef.detectChanges(); }, 1000); }
Yukarıda gördüğümüz gibi timeout fonksiyonumuzda this.changeDetectorRef.detectChanges() öğesini çağırarak manuel olarak CD'yi zorlayabiliriz. Sayaç herhangi bir şekilde şablon içinde kullanılırsa değeri yenilenecektir.
Bu bölümdeki son ipucu, belirli bileşenler için CD'yi kalıcı olarak devre dışı bırakmakla ilgilidir. Statik bir bileşenimiz varsa ve durumunun değişmemesi gerektiğinden eminsek, CD'yi kalıcı olarak devre dışı bırakabiliriz:
this.changeDetectorRef.detach()
Veri yenilemeyi devre dışı bırakmadan önce görünümümüzün doğru bir şekilde oluşturulduğundan emin olmak için bu kod ngAfterViewInit() veya ngAfterViewChecked() yaşam döngüsü yöntemi içinde yürütülmelidir. DedektifChanges()'i manuel olarak tetiklemedikçe, bu bileşen artık CD sırasında kontrol edilmeyecektir.
Şablondaki işlev çağrıları ve alıcılar
Şablonların içindeki işlev çağrılarını kullanmak, Değişiklik Dedektörü her çalıştığında bu işlevi yürütür. Aynı durum alıcılarda da olur. Mümkünse bundan kaçınmaya çalışmalıyız. Çoğu durumda, her CD çalışması sırasında bileşenin şablonunda herhangi bir işlevi yürütmemize gerek yoktur. Bunun yerine saf borular kullanabiliriz.
saf borular
Saf borular , hiçbir yan etkisi olmayan, yalnızca girdisine bağlı bir çıktıya sahip bir tür borudur. Neyse ki, Angular'daki tüm borular varsayılan olarak saftır.
@Boru({ isim: 'büyük harf', saf: doğru })
Ama neden saf: false ile boru kullanmaktan kaçınmalıyız? Cevap yine Değişiklik Algılama'dır. Saf olmayan borular, çoğu durumda gerekli olmayan her CD çalışmasında yürütülür ve uygulamamızın performansını düşürür. Saf boruya değiştirebileceğimiz fonksiyon örneği:
transform(değer: string, limit = 60, üç nokta = '...') { if (!değer || değer.uzunluk <= limit) { geri dönüş değeri; } const numberOfVisibleCharacters = value.substr(0, limit).lastIndexOf(' '); `${value.substr(0, numberOfVisibleCharacters)}${Elipsis}` döndür; }
Ve görünümü görelim:
<p class="description">kesme(metin, 30)</p>
Yukarıdaki kod saf işlevi temsil eder - yan etkisi yoktur, çıktı yalnızca girdilere bağlıdır. Bu durumda, bu işlevi saf boru ile değiştirebiliriz:
@Boru({ isim: 'kesmek', saf: doğru }) dışa aktarma sınıfı TruncatePipe, PipeTransform'u uygular { transform(değer: string, limit = 60, üç nokta = '...') { ... } }
Ve son olarak, bu görünümde, Change Detection'dan bağımsız olarak, yalnızca metin değiştirildiğinde yürütülecek kodu alıyoruz.
<p class="description">{{ metin | kes: 30 }}</p>
Tembel yükleme ve ön yükleme modülleri
Uygulamanız birden fazla sayfaya sahip olduğunda, özellikle tembel yükleme modülleri olmak üzere projenizin her mantıksal parçası için modüller oluşturmayı kesinlikle düşünmelisiniz. Basit Açısal yönlendirici kodunu ele alalım:

const rotalar: Rotalar = [ { yol: '', bileşen: Ana Bileşen }, { yol: 'foo', loadChildren: ()=> import("./foo/foo.module").then(m => m.FooModule) }, { yol: 'çubuk', loadChildren: ()=> import("./bar/bar.module").then(m => m.BarModule) } ] @NgModule({ dışa aktarma: [RouterModule], içe aktarma: [RouterModule.forRoot(routes)] }) sınıf AppRoutingModule {}
Yukarıdaki örnekte, tüm varlıklarıyla birlikte fooModule'un yalnızca kullanıcı belirli bir rotayı (foo veya bar) girmeye çalıştığında yükleneceğini görebiliriz. Angular ayrıca bu modül için ayrı bir yığın oluşturacaktır. Tembel yükleme , ilk yükü azaltacaktır.
Biraz daha optimizasyon yapabiliriz. Uygulama yükleme modüllerimizi arka planda yapmak istediğimizi varsayalım. Bu durumda preloadingStrategy'yi kullanabiliriz. Angular'ın varsayılan olarak iki tür ön yükleme Stratejisi vardır:
- Ön Yükleme Yok
- PreloadAllModüller
Yukarıdaki kodda, varsayılan olarak NoPreloading stratejisi kullanılır. Uygulama, kullanıcı isteğiyle (kullanıcı belirli bir rotayı görmek istediğinde) belirli bir modülü yüklemeye başlar. Yönlendiriciye bazı ekstra yapılandırmalar ekleyerek bunu değiştirebiliriz.
@NgModule({ dışa aktarma: [RouterModule], içe aktarma: [RouterModule.forRoot(rotalar, { preloadingStrateji: PreloadAllModules }] }) sınıf AppRoutingModule {}
Bu yapılandırma, mevcut rotanın mümkün olan en kısa sürede gösterilmesine neden olur ve bundan sonra uygulama arka planda diğer modülleri yüklemeye çalışacaktır. Akıllı, değil mi? Ama hepsi bu değil. Bu çözüm ihtiyaçlarımıza uymuyorsa, kendi özel stratejimizi yazabiliriz.
Yalnızca seçili modülleri, örneğin BarModule'ü önceden yüklemek istediğimizi varsayalım. Bunu veri alanı için fazladan bir alan ekleyerek belirtiyoruz.
const rotalar: Rotalar = [ { yol: '', bileşen: Ana Bileşen veri: { ön yükleme: yanlış } }, { yol: 'foo', loadChildren: ()=> import("./foo/foo.module").then(m => m.FooModule), veri: { ön yükleme: yanlış } }, { yol: 'çubuk', loadChildren: ()=> import("./bar/bar.module").then(m => m.BarModule), veri: { ön yükleme: doğru } } ]
Ardından özel önyükleme işlevimizi yazmalıyız:
@Enjekte edilebilir() dışa aktarma sınıfı CustomPreloadingStrategy, PreloadingStrategy'yi uygular { preload(route: Route, load: () => Gözlenebilir<any>): Gözlenebilir<any> { route.data && route.data.preload döndürmek mi? yük() : of(boş); } }
Ve bunu bir ön yükleme Stratejisi olarak ayarlayın:
@NgModule({ dışa aktarma: [RouterModule], içe aktarma: [RouterModule.forRoot(rotalar, { önyüklemeStratejisi: ÖzelÖnyüklemeStratejisi }] }) sınıf AppRoutingModule {}
Şimdilik sadece { data: { preload: true } } paramına sahip rotalar önceden yüklenecek. Rotaların geri kalanı, NoPreloading ayarlanmış gibi davranacaktır.
Özel preloadingStrategy @Injectable()'dır, bu nedenle eğer gerekirse bazı hizmetleri içeri enjekte edebiliriz ve preloadingStrategy'mizi başka bir şekilde özelleştirebiliriz.
Bir tarayıcının geliştirici araçlarıyla, bir preloadingStrategy ile ve olmadan eşit ilk yükleme süresiyle performans artışını araştırabiliriz. Ayrıca, kullanıcı herhangi bir gecikme olmadan geçerli sayfayı görebilirken, diğer rotaların parçalarının arka planda yüklendiğini görmek için ağ sekmesine de bakabiliriz.
trackBy işlevi
Angular uygulamalarının çoğunun, şablon içinde listelenen öğeleri yinelemek için *ngFor kullandığını varsayabiliriz. Yinelenen liste de düzenlenebilirse, trackBy kesinlikle sahip olunması gereken bir şeydir.
<ul> <tr *ngFor="ürünlerin ürününü ver; trackBy: trackByProductId"> <td>{{ product.title }}</td> </tr> </ul> trackByProductId(dizin: sayı, ürün: Ürün) { iade product.id; }
Angular, trackBy işlevini kullanarak, koleksiyonların hangi öğelerinin değiştiğini (verilen tanımlayıcı ile) izleyebilir ve yalnızca bu belirli öğeleri yeniden oluşturabilir. trackBy'yi atladığımızda, tüm liste yeniden yüklenecek ve bu da DOM üzerinde çok kaynak gerektiren bir işlem olabilir.
Zamanın ötesinde (AOT) derleme
Açısal belgelerle ilgili olarak:
“ (…)Angular tarafından sağlanan bileşenler ve şablonlar doğrudan tarayıcı tarafından anlaşılamaz, Angular uygulamaları bir tarayıcıda çalıştırılmadan önce bir derleme işlemi gerektirir ”
Angular, iki tür derleme sağlar:
- Just-in-Time (JIT) - çalışma zamanında tarayıcıda bir uygulama derler
- Ahead-of-Time (AOT) – bir uygulamayı derleme zamanında derler
Geliştirme kullanımı için JIT derlemesi geliştirici ihtiyaçlarını karşılamalıdır. Yine de, üretim inşası için kesinlikle AOT kullanmalıyız. angular.json dosyasındaki aot bayrağının true olarak ayarlandığından emin olmamız gerekiyor. Böyle bir çözümün en önemli faydaları arasında daha hızlı oluşturma, daha az eşzamansız istek, daha küçük çerçeve indirme boyutu ve artırılmış güvenlik yer alır.
Özet
Uygulamanın performansı, projenizin hem geliştirme hem de bakım bölümü sırasında aklınızda bulundurmanız gereken bir şeydir. Ancak olası çözümleri kendi başınıza aramak hem zaman hem de çaba harcayabilir. Yaygın olarak yapılan bu hataları kontrol etmek ve geliştirme sürecinde bunları akılda tutmak, yalnızca Angular uygulamanızın performansını kısa sürede iyileştirmenize yardımcı olmakla kalmaz, aynı zamanda gelecekteki hataları önlemenize de yardımcı olur.
Angular projenizde Miquido'ya güvenin
Bize UlaşınMiquido ile bir uygulama geliştirmek ister misiniz?
Angular uygulamasıyla işletmenizi güçlendirmeyi mi düşünüyorsunuz? Bizimle iletişime geçin ve Angular uygulama geliştirme hizmetlerimizi seçin.