
Angular 6 memperkenalkan sintaks baru yang ditingkatkan untuk menanamkan dependensi layanan dalam aplikasi (
ProvidIn ). Terlepas dari kenyataan bahwa 7 Angular telah dirilis, topik ini masih relevan.
Ada banyak kebingungan dalam komentar GitHub, Slack, dan Stack Overflow, jadi mari kita lihat lebih dekat topik ini.
Dalam artikel ini kami akan mempertimbangkan:
- Ketergantungan injeksi
- Cara lama untuk menyuntikkan dependensi ke Angular ( penyedia: [] );
- Cara baru untuk menyuntikkan dependensi dalam Angular ( tersedia di: 'root' | SomeModule );
- Skenario UseIn menyediakanIn ;
- Rekomendasi untuk menggunakan sintaks baru dalam aplikasi;
- Untuk meringkas.
Injeksi Ketergantungan
Anda dapat melewati bagian ini jika Anda sudah memiliki gagasan tentang
DI .
Dependency injection ( DI ) adalah cara untuk membuat objek yang bergantung pada objek lain. Sistem injeksi dependensi menyediakan objek tergantung ketika instantiate kelas.
- Dokumentasi Sudut
Penjelasan formal itu bagus, tapi mari kita lihat lebih dekat apa itu injeksi ketergantungan.
Semua komponen dan layanan adalah kelas. Setiap kelas memiliki metode
konstruktor khusus, yang, ketika dipanggil, membuat objek instance dari kelas ini, yang digunakan dalam aplikasi.
Misalkan di salah satu layanan kami ada kode berikut:
constructor(private http: HttpClient)
Jika Anda membuatnya tanpa menggunakan mekanisme injeksi ketergantungan, Anda harus menambahkan
HttpClient secara manual. Maka kode akan terlihat seperti ini:
const myService = new MyService(httpClient)
Tapi di mana dalam hal ini untuk mendapatkan
httpClient ? Itu juga harus dibuat:
const httpClient = new HttpClient(httpHandler)
Tapi di mana mendapatkan
httphandler sekarang? Dan seterusnya, sampai semua kelas yang diperlukan dipakai. Seperti yang bisa kita lihat, pembuatan manual bisa rumit dan kesalahan dapat terjadi dalam proses.
Mekanisme injeksi dependensi sudut melakukan semua ini secara otomatis. Yang perlu kita lakukan adalah menentukan dependensi dalam konstruktor komponen dan mereka akan ditambahkan tanpa upaya dari pihak kita.Cara lama untuk menyuntikkan dependensi dalam Angular (penyedia: [])
Untuk menjalankan aplikasi, Angular perlu tahu tentang setiap objek individu yang ingin kita terapkan dalam komponen dan layanan. Sebelum rilis Angular 6, satu-satunya cara untuk melakukan ini adalah menentukan layanan di properti
penyedia: [] dekorator
@NgModule ,
@Component dan
@Directive .

Berikut adalah tiga kegunaan utama
penyedia: [] :
- Dalam dekorator @NgModule dari modul yang segera dimuat ( bersemangat );
- Dalam dekorator @NgModule dari modul pemuatan yang tertunda ( malas );
- Di dekorator @Component dan @Directive .
Modul yang diunduh dengan aplikasi (Eager)
Dalam hal ini, layanan terdaftar dalam lingkup global sebagai singleton. Ini akan menjadi singleton walaupun disertakan dalam
penyedia [] beberapa modul. Sebuah instance dari kelas layanan dibuat yang akan didaftarkan pada level root aplikasi.
Modul Beban Ditangguhkan (Malas)
Mesin virtual dari layanan yang terhubung ke modul
malas akan dibuat selama inisialisasi. Menambahkan layanan seperti itu ke komponen
eager modul akan menghasilkan kesalahan:
Tidak ada penyedia untuk MyService! kesalahan .
Implementasi dalam @ Component dan @ Directive
Ketika diimplementasikan dalam komponen atau arahan, turunan terpisah dari layanan dibuat, yang akan tersedia dalam komponen ini dan semua anak.
Dalam situasi ini, layanan tidak akan menjadi singleton, instance-nya akan dibuat setiap kali komponen digunakan dan dihapus bersama dengan penghapusan komponen dari DOM.
Dalam hal ini,
RandomService tidak diimplementasikan pada level modul dan bukan singleton,
tetapi terdaftar dengan
penyedia: [] dari komponen
RandomComponent . Akibatnya, kami akan mendapatkan nomor acak baru setiap kali menggunakan
<randm> </ randm> .
Cara baru untuk menyuntikkan dependensi dalam Angular (tersedia di: 'root' | SomeModule)
Di Angular 6, kami mendapat alat
"Tree-shakable penyedia" baru untuk
menyuntikkan dependensi ke dalam aplikasi, yang dapat digunakan menggunakan properti
In yang disediakan dari dekorator
@Injectable .
Anda dapat membayangkan asalkan sebagai implementasi dependensi dalam arah yang berlawanan: sebelum modul menggambarkan layanan di mana ia akan terhubung, sekarang layanan mendefinisikan modul yang terhubung.Layanan ini dapat disematkan di root aplikasi (
disediakan di: 'root' ) atau di modul apa saja (
disediakan di: SomeModule ).
asalkan Di: 'root' adalah singkatan untuk implementasi di
AppModule .

Mari kita menganalisis skenario utama untuk menggunakan sintaks baru:
- Implementasi dalam modul root aplikasi ( tersedia di: 'root' );
- Implementasi dalam modul yang segera dimuat ( bersemangat );
- Implementasi dalam modul dengan loading tertunda ( malas ).
Implementasi dalam modul root aplikasi (tersedia di: 'root')
Ini adalah opsi injeksi ketergantungan yang paling umum. Dalam hal ini, layanan akan ditambahkan ke aplikasi bundel hanya jika itu benar-benar digunakan, mis. tertanam dalam komponen atau layanan lain.
Saat menggunakan pendekatan baru, tidak akan ada banyak perbedaan dalam aplikasi SPA monolitik, di mana semua layanan tertulis digunakan, namun jika
disediakan: 'root' akan berguna saat menulis perpustakaan.
Sebelumnya, semua layanan perpustakaan perlu ditambahkan ke
penyedia: [] modulnya. Setelah mengimpor perpustakaan ke dalam aplikasi, semua layanan ditambahkan ke bundel, bahkan jika hanya satu yang digunakan. Dalam hal
disediakanIn: 'root' tidak perlu menghubungkan modul perpustakaan. Cukup sematkan layanan di komponen yang diinginkan.
Modul pemuatan yang tertunda (malas) dan disediakanIn: 'root'
Apa yang terjadi jika Anda mengimplementasikan layanan dengan
providedIn: 'root' di modul
malas ?
Secara teknis,
'root' adalah singkatan dari
AppModule , tetapi Angular cukup pintar untuk menambahkan layanan ke kumpulan modul yang
malas jika hanya diimplementasikan dalam komponen dan layanannya. Tetapi ada satu masalah (meskipun beberapa orang mengklaim bahwa ini adalah fitur). Jika nanti Anda memperkenalkan layanan yang hanya digunakan dalam modul
malas ke modul utama, layanan akan ditransfer ke bundel utama. Dalam aplikasi besar dengan banyak modul dan layanan, ini dapat menyebabkan masalah pelacakan ketergantungan dan perilaku yang tidak dapat diprediksi.
Berhati-hatilah! Menerapkan satu layanan dalam banyak modul dapat menyebabkan ketergantungan tersembunyi yang sulit dipahami dan tidak mungkin terurai.Untungnya, ada cara untuk mencegah hal ini, dan kami akan mempertimbangkannya di bawah ini.
Ketergantungan injeksi dalam modul yang segera dimuat (bersemangat)
Sebagai aturan, kasus ini tidak masuk akal dan sebagai gantinya kita dapat menggunakan
asalkan dalam: 'root' . Menghubungkan layanan di
EagerModule dapat digunakan untuk enkapsulasi dan akan mencegah implementasi tanpa menghubungkan modul, tetapi dalam kebanyakan kasus ini tidak diperlukan.
Jika Anda benar-benar perlu membatasi ruang lingkup layanan, lebih mudah untuk menggunakan
penyedia lama
: [] metode, karena itu pasti tidak akan mengarah pada ketergantungan siklik.
Jika memungkinkan, coba gunakan yang disediakan di: 'root' di semua modul bersemangat.Catatan Keuntungan dari modul pemuatan yang tertunda (malas)
Salah satu fitur utama Angular adalah kemampuan untuk dengan mudah membagi aplikasi menjadi fragmen, yang memberikan keuntungan sebagai berikut:
- Ukuran kecil bundel utama aplikasi, karena itu aplikasi memuat dan mulai lebih cepat;
- Modul pemuatan yang tertunda terisolasi dengan baik dan terhubung dalam aplikasi sekali di properti loadChildren dari rute yang sesuai.
Berkat pemuatan yang tertunda, seluruh modul dengan ratusan layanan dan komponen dapat dihapus atau dipindahkan ke aplikasi atau perpustakaan terpisah, dengan sedikit atau tanpa usaha.Keuntungan lain dari isolasi modul
lazy adalah kesalahan yang dibuat di dalamnya tidak akan mempengaruhi sisa aplikasi. Sekarang Anda dapat tidur nyenyak bahkan pada hari pelepasan.
Implementasi dalam modul dengan pemuatan yang tertunda (tersedia di: LazyModule)

Ketergantungan injeksi ke modul tertentu mencegah penggunaan layanan di bagian lain dari aplikasi. Ini mempertahankan struktur dependensi, yang sangat berguna untuk aplikasi besar di mana injeksi dependensi yang berantakan dapat menyebabkan kebingungan.
Fakta menarik: Jika Anda menerapkan layanan malas di bagian utama aplikasi, majelis (bahkan AOT) akan gagal tanpa kesalahan, tetapi aplikasi akan macet dengan kesalahan "Tidak ada penyedia untuk LazyService".Masalah dengan ketergantungan siklik

Anda dapat mereproduksi kesalahan sebagai berikut:
- Buat modul LazyModule ;
- Kami membuat layanan LazyService dan terhubung menggunakan yang disediakan Di: LazyModule ;
- Kami membuat komponen LazyComponent dan menghubungkannya ke LazyModule ;
- Tambahkan LazyService ke konstruktor komponen LazyComponent ;
- Kami mendapatkan kesalahan dengan ketergantungan siklik.
Secara skematis, tampilannya seperti ini:
service -> module -> component -> service .
Anda dapat memecahkan masalah ini dengan membuat submodule
LazyServiceModule , yang akan terhubung ke
LazyModule . Hubungkan layanan ke submodule.

Dalam hal ini, Anda harus membuat modul tambahan, tetapi tidak membutuhkan banyak usaha dan akan memberikan keuntungan sebagai berikut:
- Ini akan mencegah pengenalan layanan dalam modul aplikasi lain;
- Layanan akan ditambahkan ke bundel hanya jika tertanam dalam komponen atau layanan lain yang digunakan dalam modul.
Menyematkan layanan ke dalam komponen (tersedia di: SomeComponent)
Apakah mungkin untuk menyematkan layanan di
@Component atau
@Directive menggunakan sintaks baru?
Tidak saat ini!Untuk membuat turunan dari layanan untuk setiap komponen, Anda masih perlu menggunakan
penyedia: [] di
@ omponent atau
@Directive dekorator .

Praktik Terbaik untuk Menggunakan Sintaks Baru dalam Aplikasi
Perpustakaan
asalkan: 'root' baik untuk membuat perpustakaan. Ini adalah cara yang sangat nyaman untuk menghubungkan hanya bagian yang langsung digunakan dari fungsi ke aplikasi utama dan mengurangi ukuran perakitan akhir.
Salah satu contoh praktis adalah perpustakaan ngx-model , yang telah ditulis ulang menggunakan sintaks baru dan sekarang disebut @ angular-extensions / model . Dalam implementasi baru, tidak perlu menghubungkan NgxModelModule ke aplikasi, cukup dengan menanamkan ModelFactory ke dalam komponen yang diperlukan. Detail implementasi dapat ditemukan di sini .Modul Unduhan Tangguhan (malas)
Gunakan modul terpisah yang
disediakan Di: LazyServicesModule untuk layanan dan hubungkan ke
LazyModule . Pendekatan ini merangkum layanan dan mencegah mereka terhubung ke modul lain. Ini akan menetapkan batas-batas dan membantu menciptakan arsitektur yang dapat diskalakan.
Dalam pengalaman saya, pengenalan yang tidak disengaja ke modul utama atau tambahan (menggunakan providedIn: 'root') dapat menyebabkan kebingungan dan bukan solusi terbaik!asalkan: 'root' akan bekerja dengan benar juga, tetapi ketika menggunakan
disediakan di: LazyServideModule kita mendapatkan kesalahan
"penyedia hilang" ketika diterapkan dalam modul lain dan kita dapat memperbaiki arsitektur.
Pindahkan layanan ke tempat yang lebih tepat di bagian utama aplikasi.Kapan penyedia harus digunakan: []?
Dalam kasus di mana perlu untuk mengkonfigurasi modul. Misalnya, hubungkan layanan hanya ke
SomeModule.forRoot (someConfig) .
Di sisi lain, dalam situasi ini, Anda dapat menggunakan providedIn: 'root'. Ini akan menjamin bahwa layanan akan ditambahkan ke aplikasi hanya sekali.Kesimpulan
- Gunakan yang disediakan Di: 'root' untuk mendaftarkan layanan sebagai singleton, tersedia di seluruh aplikasi.
- Untuk modul yang termasuk dalam bundel utama, gunakan yang disediakan Di: 'root' , tidak disediakan Di: EagerlyImportedModule . Dalam kasus luar biasa, gunakan penyedia: [] untuk enkapsulasi.
- Buat submodule dengan layanan untuk membatasi ruang lingkup yang disediakan Di: LazyServiceModule saat menggunakan lazy loading.
- Colokkan modul LazyServiceModule ke LazyModule untuk mencegah ketergantungan melingkar.
- Gunakan penyedia: [] di @ omponent dan @Directive dekorator untuk membuat instance layanan baru untuk setiap instance komponen baru. Mesin virtual layanan juga akan tersedia di semua komponen anak.
- Selalu membatasi ruang lingkup dependensi untuk meningkatkan arsitektur dan menghindari dependensi yang membingungkan.
Referensi
Artikel asliAngular adalah komunitas berbahasa Rusia.Pertemuan Sudut di Rusia