Saya pernah membaca bahwa menyuntikkan ketika bootstrap seharusnya membuat semua anak berbagi contoh yang sama, tetapi komponen utama dan tajuk saya (aplikasi utama mencakup komponen tajuk dan router-outlet) masing-masing mendapatkan turunan terpisah dari layanan saya.
Saya memiliki FacebookService yang saya gunakan untuk melakukan panggilan ke api javascript facebook dan UserService yang menggunakan FacebookService. Inilah bootstrap saya:
bootstrap(MainAppComponent, [ROUTER_PROVIDERS, UserService, FacebookService]);
Dari pencatatan saya, sepertinya bootstrap call selesai, lalu saya melihat FacebookService kemudian UserService dibuat sebelum kode di setiap konstruktor berjalan, MainAppComponent, HeaderComponent, dan DefaultComponent:
angular
typescript
angular2-routing
angular2-services
Jason Goemaat
sumber
sumber
UserService
danFacebookService
keproviders
tempat lain?Jawaban:
Jason sepenuhnya benar! Ini disebabkan oleh cara injeksi ketergantungan bekerja. Ini didasarkan pada injektor hirarkis.
Ada beberapa injektor dalam aplikasi Angular2:
Ketika Angular2 mencoba menyuntikkan sesuatu ke dalam konstruktor komponen:
Jadi, jika Anda ingin memiliki satu singleton untuk seluruh aplikasi, Anda harus memiliki provider yang ditentukan pada level root injector atau komponen aplikasi injector.
Tapi Angular2 akan melihat pohon injektor dari bawah. Ini berarti bahwa penyedia pada level terendah akan digunakan dan cakupan instance yang terkait adalah level ini.
Lihat pertanyaan ini untuk lebih jelasnya:
sumber
Perbarui (Sudut 6 +)
Cara yang disarankan untuk membuat layanan singleton telah berubah. Sekarang disarankan untuk menentukan di
@Injectable
dekorator pada layanan yang harus disediakan di 'root'. Ini sangat masuk akal bagi saya dan tidak perlu lagi mendaftar semua layanan yang disediakan dalam modul Anda. Anda hanya mengimpor layanan ketika Anda membutuhkannya dan mereka mendaftarkan diri di tempat yang tepat. Anda juga dapat menentukan modul sehingga hanya akan disediakan jika modul diimpor.Perbarui (Sudut 2)
Dengan NgModule, cara untuk melakukannya sekarang saya pikir adalah membuat 'CoreModule' dengan kelas layanan Anda di dalamnya, dan daftar layanan di penyedia modul. Kemudian Anda mengimpor modul inti dalam modul aplikasi utama Anda yang akan memberikan satu contoh untuk setiap anak yang meminta kelas itu dalam konstruktor mereka:
CoreModule.ts
AppModule.ts
Jawaban Asli
Jika Anda mendaftar penyedia
bootstrap()
, Anda tidak perlu mendaftarkannya di dekorator komponen Anda:Bahkan mendaftarkan kelas Anda di 'penyedia' menciptakan instance baru, jika ada komponen orang tua yang mencantumkannya maka anak-anak tidak perlu, dan jika mereka melakukannya mereka akan mendapatkan instance baru.
sumber
[providers]
dalam file modul Anda, bukan dibootstrap()
, kan?ApiService
diAppModule
'sproviders
, dan dengan demikian menghindari kebutuhan untukCoreModule
? (Tidak yakin inilah yang disarankan @JasonSwett.)ApiService
di atas tetapi mengapa repot-repot untuk meletakkannya di array penyedia CoreModule dan kemudian mengimpor yang di app.module ... itu belum mengklik untuk saya, belum.TestService
ditentukan dalam modul inti dan modul aplikasi, instance tidak dibuat untuk modul karena disediakan oleh komponen sehingga sudut tidak pernah mendapatkan setinggi pohon injektor. Jadi jika Anda menyediakan layanan dalam modul Anda dan tidak pernah menggunakannya, sebuah instance sepertinya tidak akan dibuat.Saya tahu angular memiliki injector hirarkis seperti yang dikatakan Thierry.
Tapi saya punya pilihan lain di sini jika Anda menemukan kasus penggunaan di mana Anda tidak benar-benar ingin menyuntikkannya pada orang tua.
Kita dapat mencapainya dengan membuat turunan dari layanan, dan menyediakan selalu mengembalikannya.
Dan kemudian pada komponen Anda, Anda menggunakan metode pemberian kustom.
Dan Anda harus memiliki layanan tunggal tanpa bergantung pada injector hirarkis.
Saya tidak mengatakan ini adalah cara yang lebih baik, kalau-kalau ada orang yang memiliki masalah di mana injector hirarkis tidak mungkin.
sumber
SHARE_SERVICE_PROVIDER
beradaYOUR_SERVICE_PROVIDER
di komponen? Saya juga berasumsi bahwa mengimpor file layanan diperlukan seperti biasa dan konstruktor masih akan memiliki parameter tipe 'Layanan Anda', kan? Saya suka ini saya pikir, memungkinkan Anda untuk menjamin singleton dan tidak harus memastikan layanan disediakan hierarki. Ini juga memungkinkan masing-masing komponen untuk mendapatkan salinan mereka sendiri dengan hanya mendaftarkan layanan diproviders
bukan penyedia tunggal, kan?YOUR_SERVICE_PROVIDER
. Ya, semua komponen akan mendapatkan instance yang sama dengan hanya menambahkannya di penyedia.instance
properti menjadi peta contoh nilai-kunciSintaks telah diubah. Periksa tautan ini
Dependensi adalah lajang dalam lingkup injektor. Dalam contoh di bawah ini, sebuah instance HeroService tunggal dibagikan di antara para HeroesComponent dan anak-anak HeroListComponentnya.
Langkah 1. Buat kelas tunggal dengan dekorator @Injectable
Langkah 2. Suntikkan dalam konstruktor
Langkah 3. Daftarkan penyedia
sumber
Injectable
kelas saya bukan layanan dan hanya berisistatic
string untuk penggunaan global?Menambahkan
@Injectable
dekorator ke Layanan, DAN mendaftarkannya sebagai penyedia di Modul Root akan menjadikannya singleton.sumber
constructor
seperti ini:import { SomeService } from '../../services/some/some'; @Component({ selector: 'page-selector', templateUrl: 'page.html', }) export class SomePage { constructor( public someService: SomeService ) { }
ini sepertinya bekerja dengan baik untuk saya
sumber
Berikut adalah contoh kerja dengan Angular versi 2.3. Panggil saja konstruktor dari layanan dengan cara stand seperti konstruktor ini (private _userService: UserService). Dan itu akan membuat singleton untuk aplikasi.
user.service.ts
app.component.ts
sumber
A
singleton service
adalah layanan yang hanya memiliki satu instance di aplikasi.Ada (2) cara untuk menyediakan layanan tunggal untuk aplikasi Anda.
menggunakan
providedIn
properti, ataumenyediakan modul langsung di
AppModule
aplikasiMenggunakan disediakan dalam
Dimulai dengan Angular 6.0, cara yang lebih disukai untuk membuat layanan tunggal adalah dengan mengatur
providedIn
untuk root pada@Injectable()
dekorator layanan. Ini memberitahu Angular untuk menyediakan layanan di root aplikasi.Array penyedia NgModule
Dalam aplikasi yang dibangun dengan versi Angular sebelum 6.0, layanan terdaftar array penyedia NgModule sebagai berikut:
Jika ini
NgModule
adalah rootAppModule
, UserService akan menjadi singleton dan tersedia di seluruh aplikasi. Meskipun Anda mungkin melihatnya dikodekan dengan cara ini, menggunakanprovidedIn
properti@Injectable()
dekorator pada layanan itu sendiri lebih disukai pada Angular 6.0 karena membuat layanan Anda mudah diguncang.sumber
Anda dapat menggunakan
useValue
penyediasumber
useValue
tidak terkait dengan singleton. Usevalue hanya untuk melewatkan nilai alih-alihType
(useClass
) yang memanggil DInew
atauuseFactory
ketika fungsi dilewatkan yang mengembalikan nilai ketika dipanggil oleh DI. Angular DI mempertahankan satu instance per penyedia secara otomatis. Hanya berikan sekali saja dan Anda memiliki singleton. Maaf, saya harus mengundurkan diri karena itu hanya informasi yang tidak valid: - /Dari Angular @ 6, Anda dapat memiliki
providedIn
dalamInjectable
.Periksa dokumen di sini
sumber
public static
.Cukup nyatakan layanan Anda sebagai penyedia di app.module.ts saja.
Itu berhasil bagi saya.
lalu instanciate dengan menggunakan parameter pribadi konstruktor:
atau karena jika layanan Anda digunakan dari html, opsi -prod akan mengklaim:
tambahkan anggota untuk layanan Anda dan isi dengan instance yang diterima di konstruktor:
sumber
Jika Anda ingin membuat layanan singleton pada level aplikasi, Anda harus mendefinisikannya app.module.ts
penyedia: [MyApplicationService] (Anda dapat menentukan modul anak yang sama juga untuk membuatnya spesifik modul)
Jika Anda ingin mendefinisikan layanan singleton pada tingkat komponen, buat layanan, tambahkan layanan itu di app.module.ts dan tambahkan array penyedia di dalam komponen tertentu seperti yang ditunjukkan dalam snipet di bawah ini.
@Component ({selector: 'app-root', templateUrl: './test.component.html', styleUrls: ['./test.component.scss'], penyedia: [TestMyService]})
Angular 6 menyediakan cara baru untuk menambahkan layanan di tingkat aplikasi. Alih-alih menambahkan kelas layanan ke array penyedia [] di AppModule, Anda dapat mengatur konfigurasi berikut di @Injectable ():
@Injectable ({providedIn: 'root'}) kelas ekspor MyService {...}
"Sintaks baru" memang menawarkan satu keuntungan: Layanan dapat dimuat dengan malas oleh Angular (di belakang layar) dan kode redundan dapat dihapus secara otomatis. Ini dapat menghasilkan kinerja dan kecepatan pemuatan yang lebih baik - meskipun ini sebenarnya hanya cocok untuk layanan dan aplikasi yang lebih besar secara umum.
sumber
Selain jawaban yang sangat bagus di atas, mungkin ada hal lain yang hilang jika hal-hal di singleton Anda masih belum berlaku sebagai singleton. Saya mengalami masalah ketika memanggil fungsi publik pada singleton dan menemukan bahwa itu menggunakan variabel yang salah. Ternyata masalahnya
this
adalah tidak dijamin terikat dengan singleton untuk setiap fungsi publik di singleton. Ini dapat diperbaiki dengan mengikuti saran di sini , seperti:Atau, Anda dapat dengan mudah mendeklarasikan anggota kelas sebagai
public static
gantipublic
, maka konteksnya tidak masalah, tetapi Anda harus mengaksesnya sepertiSubscriptableService.onServiceRequested$
bukannya menggunakan injeksi ketergantungan dan mengaksesnya melaluithis.subscriptableService.onServiceRequested$
.sumber
Layanan orangtua dan anak
Saya mengalami masalah dengan layanan orang tua dan anaknya menggunakan contoh yang berbeda. Untuk memaksa satu instance digunakan, Anda dapat alias induk dengan referensi ke anak di penyedia modul aplikasi Anda. Orang tua tidak akan dapat mengakses properti anak, tetapi contoh yang sama akan digunakan untuk kedua layanan. https://angular.io/guide/dependency-injection-providers#aliased-class-providers
app.module.ts
Layanan yang digunakan oleh komponen di luar ruang lingkup modul aplikasi Anda
Saat membuat perpustakaan yang terdiri dari komponen dan layanan, saya mengalami masalah di mana dua contoh akan dibuat. Satu oleh proyek Angular saya dan satu oleh komponen di dalam perpustakaan saya. Cara mengatasinya:
my-outside.component.ts
my-inside.component.ts
my-inside.component.hmtl
sumber