angular依賴注入
by Neeraj Dana
由Neeraj Dana
In this article, we will see how the dependency injection of Angular works internally. Suppose we have a component named appcomponent which has a basic and simple structure as follows:
在本文中,我們將看到Angular的依賴項注入在內部如何工作。 假設我們有一個名為appcomponent的組件,它具有如下基本且簡單的結構:
import { Component, OnInit } from "@angular/core";@Component({ selector: "my-root", templateUrl: "app.component.html", styleUrls: ["app.component.css"]})export class AppComponent implements OnInit { ngOnInit(): void { }}
And we have a service class named GreetingService with a function in it sayHello
which has a name as a parameter and returns the name with “Hello” in front of it.
我們有一個名為GreetingService的服務類,其中帶有一個函數sayHello
,該函數具有一個名稱作為參數,并在其前面返回名稱為“ Hello”的名稱。
export class GreetingService{ sayHello(name){ return `Hello ${name}` ; }}
There are two ways to use the service class in the component: first, we can manually create an instance of the service in the component (this is the wrong way and is never recommended).
在組件中使用服務類的方式有兩種:首先,我們可以在組件中手動創建服務的實例(這是錯誤的方式,從不推薦)。
And the other way is to let Angular create the instance of our service and pass that instance to our component internally. This is the common and recommended way to do it.
另一種方法是讓Angular創建服務實例并將該實例內部傳遞給我們的組件。 這是常用的推薦方法。
將我們的服務注入Angular依賴注入系統 (Injecting our service in the Angular dependency injection system)
Import {Component} from '@angular/core';Import {GreetingService} from '. /greetingService';
@Component({ selector: 'my-app', templateUrl: './app.component.html', styleUrls: [ './app.component.css' ]})export class AppComponent {
constructor(private greetingService : GreetingService){ console.log(this.greetingService.sayHello()); }}
Now if you run this project, you will get the error “No provider for GreetingService!”
現在,如果您運行此項目,您將收到錯誤“ No GreetingService沒有提供者!”。
So, basically Angular is complaining that it did not find any provider for creating an instance of the greeting service or it does not know how to create an instance. In order to let the framework know how the instance should be created, we have to pass a provider object to the providers property in the component decorator shown below:
因此,基本上Angular抱怨它沒有找到任何創建問候服務實例的提供程序,或者它不知道如何創建實例。 為了讓框架知道如何創建實例,我們必須將提供程序對象傳遞給組件裝飾器中的providers屬性,如下所示:
import { Component } from '@angular/core';import {GreetingService} from './greetingService';
@Component({ selector: 'my-app', templateUrl: './app.component.html', styleUrls: [ './app.component.css' ], providers:[{ }]})export class AppComponent {
constructor(private greetingService : GreetingService){ console.log(this.greetingService.sayHello()); } }
In this provider object, we have many properties so let us understand them one by one.
在此提供程序對象中,我們有許多屬性,因此讓我們一一理解它們。
定制工廠 (Custom Factory)
use factory: this will tell the framework which factory will be used while creating the object of the service. In our case, we don’t have any factory so let’s create one.
使用工廠:這將告訴框架在創建服務對象時將使用哪個工廠。 在我們的案例中,我們沒有任何工廠,因此讓我們創建一個工廠。
The factory will be a function which will be responsible for creating and returning the object of the service.
工廠將是一個負責創建和返回服務對象的功能。
export function greetingFactory(){ return new GreetingService()};
Or more short way
export const greetingFactory= () => new GreetingService ();
自定義注入令牌 (Custom Injection Token)
The next thing is to create a property whose value will be an Injection Token instance. Using this property, the framework will uniquely identify our service and will inject the right instance of the service.
接下來的事情是創建一個屬性,其值將是“注入令牌”實例。 使用此屬性,框架將唯一地標識我們的服務,并將注入正確的服務實例。
var greetingTokken = new InjectionToken<GreetingService>("GREET_TOKEN");
So in the above snippet, we are creating an instance of the InjectionToken class and it is generic. In our case, the GreetingService instance will be injected when someone asks for the injection with name greetingToken.
因此,在上面的代碼段中,我們正在創建InjectionToken類的實例,并且它是通用的。 在我們的示例中,當有人要求使用名稱greetingToken進行注入時,將注入GreetingService實例。
So far now our code will look like this:
到目前為止,我們的代碼將如下所示:
import { Component ,InjectionToken} from '@angular/core';import {GreetingService} from './greetingService';
export const greetingTokken = new InjectionToken<GreetingService>("GREET_TOKEN");export const greetingFactory=()=> new GreetingService();@Component({ selector: 'my-app', templateUrl: './app.component.html', styleUrls: [ './app.component.css' ], providers:[{ provide : greetingTokken, useFactory : greetingFactory, }]})export class AppComponent {
constructor(private greetingService : GreetingService){ console.log(this.greetingService.sayHello()); } name = 'Angular';}
But then also we will have the same error:
但是然后我們也會有同樣的錯誤:
This is because in the constructor, where we are asking for the instance of our service, we have to tell it the unique string of our injection token that is greetingToken
.
這是因為在構造函數中,我們在其中請求服務實例時,必須告訴它注入令牌的唯一字符串,即greetingToken
。
So let’s update our code:
因此,讓我們更新代碼:
export class AppComponent {
constructor(@Inject(greetingTokken) private greetingService : GreetingService){ console.log(this.greetingService.sayHello('Neeraj')); } name = 'Angular';}
and now we will have the result that allows us to successfully pass a service from Angular dependency injection.
現在,我們將獲得的結果使我們能夠成功地通過Angular依賴項注入傳遞服務。
Now let us assume you have some nested dependencies like this:
現在讓我們假設您有一些嵌套的依賴項,如下所示:
import{DomSanitizer} from '@angular/platform-browser';
export class GreetingService{ constructor (private domSanitizer:DomSanitizer){ } sayHello(name){ return `Hello ${name}` }}
So, in this case, we have to pass one more property to the provider’s object (that is deps) which is the array of all the dependencies:
因此,在這種情況下,我們必須再傳遞一個屬性到提供者的對象(即deps),該對象是所有依賴項的數組:
@Component({ selector: 'my-app', templateUrl: './app.component.html', styleUrls: [ './app.component.css' ], providers:[{ provide : greetingTokken, useFactory : greetingFactory, deps:[DomSanitizer] }]})export class AppComponent {
constructor(@Inject(greetingTokken) private greetingService : GreetingService ){ console.log(this.greetingService.sayHello('Neeraj')); } name = 'Angular';}
Up until now, whatever we have done has only been for learning purposes. It is not recommended to create manual providers until there is a need.
到目前為止,我們所做的一切僅是出于學習目的。 不建議在需要之前創建手動提供程序。
So this is all the hard work done by Angular behind the scenes for us. We don’t have to do all this for registering our service. We can actually reduce the code, and instead of passing the factory and token manually, we can ask the framework to do this for us in that case.
因此,這就是Angular在后臺為我們完成的所有艱苦工作。 我們不必為注冊我們的服務而做所有這一切。 實際上,我們可以減少代碼,而不是手動傳遞工廠和令牌,在這種情況下,我們可以要求框架為我們這樣做。
The provide property, which is the injection token, will be the name of the service and Angular will internally create an injection token and factory for us.
提供屬性(即注入令牌)將是服務的名稱,Angular將在內部為我們創建注入令牌和工廠。
We have to pass one more property (use-class) which tells the framework which class we need to use:
我們必須再傳遞一個屬性(使用類),該屬性告訴框架我們需要使用哪個類:
import { Component ,InjectionToken,Inject} from '@angular/core';
import {GreetingService} from './greetingService';
@Component({ selector: 'my-app', templateUrl: './app.component.html', styleUrls: [ './app.component.css' ], providers:[{ provide : GreetingService, useClass :GreetingService }]})export class AppComponent {
constructor( private greetingService : GreetingService ){ console.log(this.greetingService.sayHello('Neeraj')); } name = 'Angular';}
So now our code looks much cleaner and we can further reduce it by just passing the name of the service. Then Angular under the hood will create the provide object, the factory, and the injection token for us and make the instance available to us when needed.
因此,現在我們的代碼看起來更簡潔了,我們可以通過傳遞服務名稱來進一步減少代碼。 然后,Angular在幕后將為我們創建提供對象,工廠和注入令牌,并在需要時使實例可用。
import { Component } from '@angular/core';
import {GreetingService} from './greetingService';
@Component({ selector: 'my-app', templateUrl: './app.component.html', styleUrls: [ './app.component.css' ], providers:[GreetingService]})export class AppComponent {
constructor( private greetingService : GreetingService ){ console.log(this.greetingService.sayHello('Neeraj')); } name = 'Angular';}
So in the end, our code looks very familiar. Now in the future, whenever you create a service, you know exactly what steps are involved to get that instance available.
因此,最后,我們的代碼看起來非常熟悉。 將來,無論何時創建服務,您都確切知道要使該實例可用需要執行哪些步驟。
If you like this article follow me to get more of this kind of stuff.
如果您喜歡本文,請跟隨我獲得更多此類內容。
Visit Smartcodehub
前往Smartcodehub
翻譯自: https://www.freecodecamp.org/news/angular-dependency-injection-in-detail-8b6822d6457c/
angular依賴注入