Angular 学习笔记 (五) - 服务Service和依赖注入

参考官方文档:https://angular.cn/tutorial/toh-pt4

 

一.服务

组件不应该直接获取或保存数据,它们不应该了解是否在展示假数据。 它们应该聚焦于展示数据,而把数据访问的职责委托给某个服务。

Service的作用便可以减少数据在不同模块之间的耦合,简化代码。

创建Service指令:

ng generate service hero

Service的结构:

 1 import { Injectable } from '@angular/core';
 2 
 3 @Injectable({
 4   providedIn: 'root',
 5 })
 6 export class HeroService {
 7 
 8   constructor() { }
 9 
10 }

 这里 providedIn: 'root' 的可以将Service声名为App的根目录,适用于作为一个单例服务

 

二.依赖注入

服务导入了 Angular 的 Injectable 符号,并且给这个服务类添加了 @Injectable() 装饰器。 它把这个类标记为依赖注入系统的参与者之一。

@Injectable() 装饰器会接受该服务的元数据对象,就像 @Component() 对组件类的作用一样。

你必须先注册一个服务提供者,来让 Service 在依赖注入系统中可用,Angular 才能把它注入到 Component 中。所谓服务提供者就是某种可用来创建或交付一个服务的东西;在这里,它通过实例化 HeroService 类,来提供该服务。

为了确保 HeroService 可以提供该服务,就要使用注入器来注册它。注入器是一个对象,负责当应用要求获取它的实例时选择和注入该提供者。

一个依赖注入的示例:

Recipe数据模型:

 1 import { Ingredient } from '../shared/ingredient.model';
 2 
 3 export class Recipe {
 4   public name: string;
 5   public description: string;
 6   public imagePath: string;
 7   public ingredients: Ingredient[];
 8 
 9   constructor(name: string, desc: string, imagePath: string, ingredients: Ingredient[]) {
10     this.name = name;
11     this.description = desc;
12     this.imagePath = imagePath;
13     this.ingredients = ingredients;
14   }
15 }

服务:

 1 import { EventEmitter, Injectable } from '@angular/core';
 2 
 3 import { Recipe } from './recipe.model';
 4 import { Ingredient } from '../shared/ingredient.model';
 5 import { ShoppingListService } from '../shopping-list/shopping-list.service';
 6 
 7 @Injectable()
 8 export class RecipeService {
 9   recipeSelected = new EventEmitter<Recipe>();
10 
11   private recipes: Recipe[] = [
12     new Recipe(
13       'Tasty Schnitzel',
14       'A super-tasty Schnitzel - just awesome!',
15       'https://upload.wikimedia.org/wikipedia/commons/7/72/Schnitzel.JPG',
16       [
17         new Ingredient('Meat', 1),
18         new Ingredient('French Fries', 20)
19       ]),
20     new Recipe('Big Fat Burger',
21       'What else you need to say?',
22       'https://upload.wikimedia.org/wikipedia/commons/b/be/Burger_King_Angus_Bacon_%26_Cheese_Steak_Burger.jpg',
23       [
24         new Ingredient('Buns', 2),
25         new Ingredient('Meat', 1)
26       ])
27   ];
28 
29   constructor(private slService: ShoppingListService) {}
30 
31   getRecipes() {
32     return this.recipes.slice();
33   }
34 
35   addIngredientsToShoppingList(ingredients: Ingredient[]) {
36     this.slService.addIngredients(ingredients);
37   }
38 }

这里 ShoppingListService 是另一个服务,服务中可以注入另一个服务 

 服务注入Component:

recipes.component.ts:

 1 import { Component, OnInit } from '@angular/core';
 2 
 3 import { Recipe } from './recipe.model';
 4 import { RecipeService } from './recipe.service';
 5 
 6 @Component({
 7   selector: 'app-recipes',
 8   templateUrl: './recipes.component.html',
 9   styleUrls: ['./recipes.component.css'],
10   providers: [RecipeService]
11 })
12 export class RecipesComponent implements OnInit {
13   selectedRecipe: Recipe;
14 
15   constructor(private recipeService: RecipeService) { }
16 
17   ngOnInit() {
18     this.recipeService.recipeSelected
19       .subscribe(
20         (recipe: Recipe) => {
21           this.selectedRecipe = recipe;
22         }
23       );
24   }
25 }

 

三. 依赖注入的层级

Root注入器并不是Angular应用中唯一的注入器。Modules 和 Components也有自己的注入器。Angular应用的注入器遵循一个层级制度

每当Angular组件在其构造函数中定义了Token时,注入器就会在已注册提供者池中搜索与该Token匹配的类型。如果没有匹配,它将在父组件的提供者上委托搜索,并不断向注册器树上级找寻,直到root注入器如果提供者查找结束时没有匹配,它将返回

如果没有找到匹配项,Angular就会抛出异常。

注入器树:

 

 当组件寻求依赖时:

1st pass: 组件会依次来搜寻父组件,如果找到依赖,则停止寻找并请求改实例,若没有找到,进入2nd pass

2nd pass: 组件依次搜寻其父Module直到root,如果找到依赖,则停止寻找并请求改实例,如果没有找到,则抛出error

 

posted @ 2021-04-08 10:29  Asp1rant  阅读(399)  评论(0编辑  收藏  举报