
Dokumen ini berisi daftar praktik yang akan membantu kami meningkatkan kinerja aplikasi sudut kami. "Daftar Periksa Kinerja Angular" mencakup berbagai topik-dari pra-rendering sisi server dan bundling aplikasi kami hingga kinerja runtime dan optimalisasi deteksi perubahan yang dilakukan oleh kerangka kerja.
Dokumen ini dibagi menjadi dua bagian utama:
Beberapa praktik berdampak pada kedua kategori sehingga mungkin ada sedikit persimpangan, namun, perbedaan dalam kasus penggunaan dan implikasinya akan disebutkan secara eksplisit.
Sebagian besar alat daftar subbagian, terkait dengan praktik spesifik, yang dapat membuat kami lebih efisien dengan mengotomatisasi aliran pengembangan kami.
Perhatikan bahwa sebagian besar praktik valid untuk HTTP/1.1 dan HTTP/2. Praktik yang membuat pengecualian akan disebutkan dengan menentukan versi protokol mana yang dapat diterapkan.
enableProdModeChangeDetectionStrategy.OnPush*ngFor PRANTRINGtrackByBeberapa alat di bagian ini masih dalam pengembangan dan dapat berubah. Tim inti Angular sedang berupaya mengotomatisasi proses pembangunan untuk aplikasi kami sebanyak mungkin sehingga banyak hal akan terjadi secara transparan.
Bundling adalah praktik standar yang bertujuan untuk mengurangi jumlah permintaan yang perlu dilakukan browser untuk mengirimkan aplikasi yang diminta oleh pengguna. Intinya, bundler menerima sebagai input daftar titik masuk dan menghasilkan satu atau lebih bundel. Dengan cara ini, browser dapat memperoleh seluruh aplikasi dengan hanya melakukan beberapa permintaan, alih -alih meminta setiap sumber daya individu secara terpisah.
Saat aplikasi Anda tumbuh menggabungkan semuanya menjadi satu bundel besar akan kembali kontraproduktif. Jelajahi teknik pemisahan kode menggunakan Webpack.
Permintaan HTTP tambahan tidak akan menjadi perhatian dengan HTTP/2 karena fitur Push Server.
Perkakas
Alat yang memungkinkan kami untuk mengikat aplikasi kami secara efisien adalah:
Sumber daya
Praktik -praktik ini memungkinkan kami untuk meminimalkan konsumsi bandwidth dengan mengurangi muatan aplikasi kami.
Perkakas
Sumber daya
Meskipun kita tidak melihat karakter whitespace (karakter yang cocok dengan s ), itu masih diwakili oleh byte yang ditransfer melalui jaringan. Jika kita mengurangi spasi putih dari templat kita ke minimum kita akan masing -masing dapat menjatuhkan ukuran bundel kode AOT lebih jauh.
Untungnya, kami tidak harus melakukan ini secara manual. Antarmuka ComponentMetadata menyediakan preserveWhitespaces properti yang secara default memiliki nilai false makna yang secara default kompiler sudut akan memangkas whitespace untuk mengurangi ukuran aplikasi kami. Jika kami mengatur properti ke true Angular akan mempertahankan whitespace.
Untuk versi final aplikasi kami, kami biasanya tidak menggunakan seluruh kode yang disediakan oleh Angular dan/atau perpustakaan pihak ketiga mana pun, bahkan yang telah kami tulis. Berkat sifat statis dari modul ES2015, kami dapat menyingkirkan kode yang tidak dirujuk dalam aplikasi kami.
Contoh
// foo.js
export foo = ( ) => 'foo' ;
export bar = ( ) => 'bar' ;
// app.js
import { foo } from './foo' ;
console . log ( foo ( ) ) ; Setelah kami shake pohon dan bundel app.js kami akan mendapatkan:
let foo = ( ) => 'foo' ;
console . log ( foo ( ) ) ; Ini berarti bahwa bar ekspor yang tidak digunakan tidak akan dimasukkan ke dalam bundel akhir.
Perkakas
Catatan: GCC belum mendukung export * , yang penting untuk membangun aplikasi sudut karena penggunaan berat pola "barel".
Sumber daya
Sejak rilis Angular Version 6, tim Angular menyediakan fitur baru untuk memungkinkan layanan dapat diguncang pohon, yang berarti bahwa layanan Anda tidak akan dimasukkan dalam bundel akhir kecuali mereka digunakan oleh layanan atau komponen lain. Ini dapat membantu mengurangi ukuran bundel dengan menghapus kode yang tidak digunakan dari bundel.
Anda dapat membuat layanan Anda dapat diguncang dengan menggunakan atribut providedIn untuk menentukan di mana layanan harus diinisialisasi saat menggunakan dekorator @Injectable() . Maka Anda harus menghapusnya dari atribut providers Deklarasi NgModule Anda serta pernyataan impornya sebagai berikut.
Sebelum:
// app.module.ts
import { NgModule } from '@angular/core'
import { AppRoutingModule } from './app-routing.module'
import { AppComponent } from './app.component'
import { environment } from '../environments/environment'
import { MyService } from './app.service'
@ NgModule ( {
declarations : [
AppComponent
] ,
imports : [
...
] ,
providers : [ MyService ] ,
bootstrap : [ AppComponent ]
} )
export class AppModule { } // my-service.service.ts
import { Injectable } from '@angular/core'
@ Injectable ( )
export class MyService { }Setelah:
// app.module.ts
import { NgModule } from '@angular/core'
import { AppRoutingModule } from './app-routing.module'
import { AppComponent } from './app.component'
import { environment } from '../environments/environment'
@ NgModule ( {
declarations : [
AppComponent
] ,
imports : [
...
] ,
providers : [ ] ,
bootstrap : [ AppComponent ]
} )
export class AppModule { } // my-service.service.ts
import { Injectable } from '@angular/core'
@ Injectable ( {
providedIn : 'root'
} )
export class MyService { } Jika MyService tidak disuntikkan dalam komponen/layanan apa pun, maka itu tidak akan dimasukkan dalam bundel.
Sumber daya
Tantangan bagi yang tersedia di Wild Tools (seperti GCC, Rollup, dll.) Adalah template seperti HTML dari komponen sudut, yang tidak dapat dianalisis dengan kemampuannya. Ini membuat dukungan pengocok pohon mereka kurang efisien karena mereka tidak yakin arahan mana yang dirujuk dalam templat. Kompiler AOT mentranspilasi templat seperti HTML sudut ke JavaScript atau naskah dengan impor modul ES2015. Dengan cara ini kita dapat secara efisien trikal pohon selama bundling dan menghapus semua arahan yang tidak digunakan yang ditentukan oleh perpustakaan pihak ketiga, atau oleh diri kita sendiri.
Sumber daya
Kompresi praktik standar muatan tanggapan untuk pengurangan penggunaan bandwidth. Dengan menentukan nilai header Accept-Encoding , browser mengisyaratkan server yang algoritma kompresi tersedia di mesin klien. Di sisi lain, server menetapkan nilai untuk header Content-Encoding dari respons untuk memberi tahu browser algoritma mana yang telah dipilih untuk menekan respons.
Perkakas
Perkakas di sini tidak spesifik sudut dan sepenuhnya tergantung pada server web/aplikasi yang kami gunakan. Algoritma kompresi yang khas adalah:
Sumber daya
Pra-Fetching Sumber Daya adalah cara yang bagus untuk meningkatkan pengalaman pengguna. Kami dapat membuat pra-pembangkaan aset (gambar, gaya, modul yang dimaksudkan untuk dimuat dengan malas, dll.) Atau data. Ada berbagai strategi pra-pembekuan tetapi kebanyakan dari mereka bergantung pada spesifik aplikasi.
Jika aplikasi target memiliki basis kode yang sangat besar dengan ratusan dependensi, praktik yang tercantum di atas mungkin tidak membantu kita mengurangi bundel ke ukuran yang wajar (wajar mungkin 100 ribu atau 2m, itu lagi, sepenuhnya tergantung pada tujuan bisnis).
Dalam kasus seperti itu, solusi yang baik mungkin untuk memuat beberapa modul aplikasi dengan malas. Misalnya, anggaplah kita sedang membangun sistem e-commerce. Dalam hal ini, kami mungkin ingin memuat panel admin secara independen dari UI yang menghadap pengguna. Setelah administrator harus menambahkan produk baru, kami ingin menyediakan UI yang diperlukan untuk itu. Ini bisa berupa hanya "Tambah Halaman Produk" atau seluruh panel admin, tergantung pada persyaratan penggunaan/bisnis kami.
Perkakas
Misalkan kita memiliki konfigurasi perutean berikut:
// Bad practice
const routes : Routes = [
{ path : '' , redirectTo : '/dashboard' , pathMatch : 'full' } ,
{ path : 'dashboard' , loadChildren : ( ) => import ( './dashboard.module' ) . then ( mod => mod . DashboardModule ) } ,
{ path : 'heroes' , loadChildren : ( ) => import ( './heroes.module' ) . then ( mod => mod . HeroesModule ) }
] ; Pertama kali pengguna membuka aplikasi menggunakan URL: https://example.com/ mereka akan diarahkan ke /dashboard yang akan memicu rute malas dengan dashboard jalur. Agar bersudut untuk membuat komponen bootstrap dari modul, ia harus mengunduh file dashboard.module dan semua dependensinya. Kemudian, file perlu diuraikan oleh JavaScript VM dan dievaluasi.
Memicu permintaan HTTP tambahan dan melakukan perhitungan yang tidak perlu selama pemuatan halaman awal adalah praktik yang buruk karena memperlambat rendering halaman awal. Pertimbangkan untuk mendeklarasikan rute halaman default sebagai non-lazy.
Caching adalah praktik umum lain yang berniat untuk mempercepat aplikasi kami dengan memanfaatkan heuristik bahwa jika satu sumber daya baru-baru ini diminta, itu mungkin diminta lagi dalam waktu dekat.
Untuk data caching kami biasanya menggunakan mekanisme caching khusus. Untuk caching aset statis, kita dapat menggunakan caching browser standar atau pekerja layanan dengan Cacestorage API.
Untuk membuat kinerja aplikasi Anda lebih cepat, gunakan shell aplikasi.
Shell aplikasi adalah antarmuka pengguna minimum yang kami tunjukkan kepada pengguna untuk menunjukkan bahwa aplikasi akan segera dikirimkan. Untuk menghasilkan shell aplikasi secara dinamis, Anda dapat menggunakan Angular Universal dengan arahan khusus yang secara kondisional menunjukkan elemen tergantung pada platform rendering yang digunakan (yaitu menyembunyikan semuanya kecuali shell aplikasi saat menggunakan platform-server ).
Perkakas
Sumber daya
Kita dapat menganggap pekerja layanan sebagai proxy HTTP yang terletak di browser. Semua permintaan yang dikirim dari klien pertama kali dicegat oleh pekerja layanan yang dapat menanganinya atau melewatinya melalui jaringan.
Anda dapat menambahkan pekerja layanan ke proyek angular Anda dengan menjalankan ng add @angular/pwa
Perkakas
Sumber daya
Bagian ini mencakup praktik yang dapat diterapkan untuk memberikan pengalaman pengguna yang lebih halus dengan 60 frame per detik (FPS).
enableProdModeDalam mode pengembangan, Angular melakukan beberapa pemeriksaan tambahan untuk memverifikasi bahwa melakukan deteksi perubahan tidak menghasilkan perubahan tambahan apa pun pada salah satu binding. Dengan cara ini kerangka kerja memastikan bahwa aliran data searah telah diikuti.
Untuk menonaktifkan perubahan ini untuk produksi, jangan lupa untuk meminta enableProdMode :
import { enableProdMode } from '@angular/core' ;
if ( ENV === 'production' ) {
enableProdMode ( ) ;
}AOT dapat membantu tidak hanya untuk mencapai bundling yang lebih efisien dengan melakukan pelepasan pohon, tetapi juga untuk meningkatkan kinerja runtime dari aplikasi kami. Alternatif AOT adalah kompilasi just-in-time (JIT) yang dilakukan runtime, oleh karena itu kami dapat mengurangi jumlah perhitungan yang diperlukan untuk rendering aplikasi kami dengan melakukan kompilasi sebagai bagian dari proses pembangunan kami.
Perkakas
ng serve --prodSumber daya
Masalah biasa dalam aplikasi satu halaman khas (SPA) adalah bahwa kode kami biasanya dijalankan dalam satu utas. Ini berarti bahwa jika kita ingin mencapai pengalaman pengguna yang lancar dengan 60fps yang kita miliki paling banyak 16ms untuk dieksekusi antara masing -masing frame sedang dirender, jika tidak, mereka akan turun setengah.
Dalam aplikasi yang kompleks dengan pohon komponen yang sangat besar, di mana deteksi perubahan perlu melakukan jutaan cek setiap detik, tidak akan sulit untuk mulai menjatuhkan bingkai. Berkat agnostisisme Angular dan dipisahkan dari arsitektur DOM, dimungkinkan untuk menjalankan seluruh aplikasi kami (termasuk deteksi perubahan) dalam pekerja web dan meninggalkan utas UI utama yang hanya bertanggung jawab untuk rendering.
Perkakas
Sumber daya
Masalah besar spa tradisional adalah bahwa mereka tidak dapat diterjemahkan sampai seluruh javascript yang diperlukan untuk rendering awal mereka tersedia. Ini menyebabkan dua masalah besar:
Rendering sisi server memecahkan masalah ini dengan pra-rendering halaman yang diminta di server dan memberikan markup halaman yang diberikan selama pemuatan halaman awal.
Perkakas
Sumber daya
Pada setiap peristiwa asinkron, Angular melakukan deteksi perubahan di seluruh pohon komponen. Meskipun kode yang mendeteksi perubahan dioptimalkan untuk caching inline, ini masih bisa menjadi perhitungan berat dalam aplikasi yang kompleks. Cara untuk meningkatkan kinerja deteksi perubahan adalah dengan tidak melakukannya untuk subtree yang seharusnya tidak diubah berdasarkan tindakan terbaru.
ChangeDetectionStrategy.OnPush Strategi deteksi perubahan OnPush memungkinkan kita untuk menonaktifkan mekanisme deteksi perubahan untuk subtree pohon komponen. Dengan menetapkan strategi deteksi perubahan ke komponen apa pun ke nilai ChangeDetectionStrategy.OnPush akan membuat deteksi perubahan hanya melakukan hanya ketika komponen telah menerima input yang berbeda. Angular akan menganggap input berbeda ketika membandingkannya dengan input sebelumnya dengan referensi, dan hasil dari pemeriksaan referensi false . Dalam kombinasi dengan struktur data yang tidak dapat diubah, OnPush dapat membawa implikasi kinerja yang hebat untuk komponen "murni" seperti itu.
Sumber daya
Cara lain untuk menerapkan mekanisme deteksi perubahan khusus adalah dengan detach dan memasang reattach detektor perubahan (CD) untuk diberikan komponen. Setelah kami detach sudut CD tidak akan melakukan pemeriksaan untuk seluruh subtree komponen.
Praktik ini biasanya digunakan ketika tindakan pengguna atau interaksi dengan layanan eksternal memicu deteksi perubahan lebih sering daripada yang diperlukan. Dalam kasus seperti itu, kami mungkin ingin mempertimbangkan untuk melepaskan detektor perubahan dan mengulanginya hanya ketika melakukan deteksi perubahan diperlukan.
Mekanisme deteksi perubahan Angular sedang dipicu berkat Zone.Js. Zone.js Monkey Patches Semua API asinkron di browser dan memicu deteksi perubahan pada akhir pelaksanaan panggilan balik async. Dalam kasus yang jarang terjadi , kami mungkin ingin kode yang diberikan dieksekusi di luar konteks zona sudut dan dengan demikian, tanpa menjalankan mekanisme deteksi perubahan. Dalam kasus seperti itu, kita dapat menggunakan Metode runOutsideAngular dari instance NgZone .
Contoh
Di cuplikan di bawah ini, Anda dapat melihat contoh untuk komponen yang menggunakan praktik ini. Ketika metode _incrementPoints disebut komponen akan mulai menambah properti _points setiap 10ms (secara default). Penambahan akan membuat ilusi animasi. Karena dalam hal ini, kami tidak ingin memicu mekanisme deteksi perubahan untuk seluruh pohon komponen, setiap 10ms, kami dapat menjalankan _incrementPoints di luar konteks zona sudut dan memperbarui DOM secara manual (lihat setter points ).
@ Component ( {
template : '<span #label></span>'
} )
class PointAnimationComponent {
@ Input ( ) duration = 1000 ;
@ Input ( ) stepDuration = 10 ;
@ ViewChild ( 'label' ) label : ElementRef ;
@ Input ( ) set points ( val : number ) {
this . _points = val ;
if ( this . label ) {
this . label . nativeElement . innerText = this . _pipe . transform ( this . points , '1.0-0' ) ;
}
}
get points ( ) {
return this . _points ;
}
private _incrementInterval : any ;
private _points : number = 0 ;
constructor ( private _ngZone : NgZone , private _pipe : DecimalPipe ) { }
ngOnChanges ( changes : any ) {
const change = changes . points ;
if ( ! change ) {
return ;
}
if ( typeof change . previousValue !== 'number' ) {
this . points = change . currentValue ;
} else {
this . points = change . previousValue ;
this . _ngZone . runOutsideAngular ( ( ) => {
this . _incrementPoints ( change . currentValue ) ;
} ) ;
}
}
private _incrementPoints ( newVal : number ) {
const diff = newVal - this . points ;
const step = this . stepDuration * ( diff / this . duration ) ;
const initialPoints = this . points ;
this . _incrementInterval = setInterval ( ( ) => {
let nextPoints = Math . ceil ( initialPoints + diff ) ;
if ( this . points >= nextPoints ) {
this . points = initialPoints + diff ;
clearInterval ( this . _incrementInterval ) ;
} else {
this . points += step ;
}
} , this . stepDuration ) ;
}
}PERINGATAN : Gunakan latihan ini dengan sangat hati -hati hanya ketika Anda yakin apa yang Anda lakukan karena jika tidak digunakan dengan benar dapat menyebabkan keadaan DOM yang tidak konsisten. Juga, perhatikan bahwa kode di atas tidak akan berjalan di WebWorkers. Untuk membuatnya kompatibel dengan webworker, Anda perlu mengatur nilai label dengan menggunakan renderer Angular.
Angular menggunakan zona.js untuk mencegat peristiwa yang terjadi dalam aplikasi dan menjalankan deteksi perubahan secara otomatis. Secara default ini terjadi ketika antrian mikrotask dari browser kosong, yang dalam beberapa kasus dapat menyebut siklus yang berlebihan. Dari V9, Angular menyediakan cara untuk menyatukan deteksi perubahan peristiwa dengan menyalakan ngZoneEventCoalescing , yaitu
platformBrowser ( )
. bootstrapModule ( AppModule , { ngZoneEventCoalescing : true } ) ; Konfigurasi di atas akan menjadwalkan deteksi perubahan dengan requestAnimationFrame , alih -alih terhubung ke antrian microtask, yang akan menjalankan cek lebih jarang dan mengkonsumsi lebih sedikit siklus komputasi.
Peringatan: NgzoneEventCoAlescing: Benar dapat merusak aplikasi yang ada yang menyampaikan deteksi perubahan yang secara konsisten.
Sumber daya
Sebagai argumen, dekorator @Pipe menerima objek secara literal dengan format berikut:
interface PipeMetadata {
name : string ;
pure : boolean ;
}Bendera murni menunjukkan bahwa pipa tidak tergantung pada keadaan global apa pun dan tidak menghasilkan efek samping. Ini berarti bahwa pipa akan mengembalikan output yang sama ketika dipanggil dengan input yang sama. Dengan cara ini Angular dapat menyimpan output untuk semua parameter input pipa yang telah dipanggil, dan menggunakannya kembali agar tidak harus mengkomputasi mereka pada setiap evaluasi.
Nilai default dari properti pure true .
*ngFor PRANTRING Petunjuk *ngFor digunakan untuk membuat koleksi.
trackBy Secara default *ngFor mengidentifikasi keunikan objek dengan referensi.
Yang berarti ketika pengembang memecahkan referensi ke objek selama memperbarui konten item, sudut memperlakukannya sebagai penghapusan objek lama dan penambahan objek baru. Ini efek dalam menghancurkan node dom lama dalam daftar dan menambahkan simpul Dom baru di tempatnya.
Pengembang dapat memberikan petunjuk untuk Angular cara mengidentifikasi keunikan objek: Fungsi pelacakan khusus sebagai opsi trackBy untuk arahan *ngFor . Fungsi pelacakan mengambil dua argumen: index dan item . Angular menggunakan nilai yang dikembalikan dari fungsi pelacakan untuk melacak identitas item. Sangat umum menggunakan ID dari catatan tertentu sebagai kunci unik.
Contoh
@ Component ( {
selector : 'yt-feed' ,
template : `
<h1>Your video feed</h1>
<yt-player *ngFor="let video of feed; trackBy: trackById" [video]="video"></yt-player>
`
} )
export class YtFeedComponent {
feed = [
{
id : 3849 , // note "id" field, we refer to it in "trackById" function
title : "Angular in 60 minutes" ,
url : "http://youtube.com/ng2-in-60-min" ,
likes : "29345"
} ,
// ...
] ;
trackById ( index , item ) {
return item . id ;
}
} Rendering elemen DOM biasanya merupakan operasi paling mahal saat menambahkan elemen ke UI. Pekerjaan utama biasanya disebabkan oleh memasukkan elemen ke dalam DOM dan menerapkan gaya. Jika *ngFor membuat banyak elemen, browser (terutama yang lebih tua) dapat memperlambat dan membutuhkan lebih banyak waktu untuk menyelesaikan rendering semua elemen. Ini tidak spesifik untuk sudut.
Untuk mengurangi waktu rendering, cobalah yang berikut:
*ngFor bagian template Anda. Biasanya, elemen DOM yang tidak dibutuhkan/tidak digunakan muncul dari memperpanjang templat berulang kali. Memikirkan kembali strukturnya mungkin membuat segalanya lebih mudah.ng-container jika memungkinkanSumber daya
*ngForAngular menjalankan ekspresi template setelah setiap siklus deteksi perubahan. Siklus deteksi perubahan dipicu oleh banyak kegiatan asinkron seperti resolusi janji, hasil HTTP, peristiwa pengatur waktu, penekanan kunci, dan gerakan tikus.
Ekspresi harus selesai dengan cepat atau pengalaman pengguna dapat menyeret, terutama pada perangkat yang lebih lambat. Pertimbangkan nilai caching saat perhitungannya mahal.
Sumber daya
Daftar praktik akan berkembang secara dinamis dari waktu ke waktu dengan praktik baru/diperbarui. Jika Anda melihat sesuatu yang hilang atau Anda berpikir bahwa salah satu praktik dapat ditingkatkan, jangan ragu untuk memecat masalah dan/atau PR. Untuk informasi lebih lanjut, silakan lihat bagian "berkontribusi" di bawah ini.
Jika Anda melihat sesuatu yang hilang, tidak lengkap atau salah, permintaan tarik akan sangat dihargai. Untuk diskusi praktik yang tidak termasuk dalam dokumen, harap buka masalah.
Mit