首页 >> 大全

Angular7知识点8----服务提供商

2023-09-08 大全 27 作者:考证青年

这一章我们来了解一下依赖注入系统中一个很重要的概念——服务提供商,有人使用服务,那么就应该有人提供服务吧!这样理解有没有简单些,实际上,就是这样的!(等阅读完这一节你就会明白)

心法篇 详细教程篇

1、服务提供商的原型

服务提供商是一个对象,它会告诉怎样来找到对应的服务(通过DI令牌)、以及如何创建服务实例,不知道你是否还记得——不管是组件元数据对象的属性还是模块元数据对象的属性,对的描述都是:表示服务提供商列表!!!这时候,你可能会反驳了,怎么前面一章“依赖注入系统之服务”其中的元数据对象的数组中就只有一个类名,难道这就是服务提供商?没错,就是服务提供商,只不过是这种服务提供商的简写形式,现在我们来解开服务提供商的神秘面纱

服务提供商的原型

{provide: DI令牌, useClass/useExisting/useValue/useFactory: 服务类名}

吊炸天是吧!而下面的两种写法是等价的

providers:[LoggerService] 
<=> 
providers:[{provider: LoggerService, useClass: LoggerService}]

现在是不是对前一章的那种写法有清晰的认识了呢!现在。我们只需要记住这个原型即可,在记住这个原型后,请继续往下看

2、DI令牌

前面多次讲到,DI令牌是用来查找服务的,那么,我们怎样使用呢?或许,你应该看到这样的写法

constructor(private loggerService: LoggerService) {}

告诉你一个小秘密,DI令牌就藏在其中,而数组中的内容是这样的

  providers: [LoggerService]

或许你已经猜到!没错这里的DI令牌就是,所以下面这段话很重要——写在构造函数中的那个你以为是服务类的类名其实是DI令牌!这个例子其实并没有将这段话的意思表达的淋漓尽致,请继续往下看(这个类用来创建DI令牌),在这里我们只需要有这么一个印象就好了

3、服务提供商

这或许是最近经常使用的,也最简单的服务提供商了,在前面你也接触过,在这里就不多讲了,但需要注意的是

providers:[LoggerService] 

会帮我们new出一个的实例

4、服务提供商

或者你也可以叫它别名提供商,为什么这么叫呢,从字面上来说是“使用存在"的意思,其实没毛病,就是使用存在的服务实例!官方有一个很好的例子,我在这里引用一下:别名提供商

想象有这样的一个场景:原本应用中有一个名叫的服务类,现在我们需要使用一个新的名叫的服务。而这两个服务类的接口相同,出于某种原因,我们没法修改老的组件来使用,而你的想法是:当来组件使用来记录信息时,你希望它使用的是的实例而不是的实例,为了达到这个目的,我们就可以使用这种类别的提供商,代码如下

providers: [ NewLoggerService, { provide: OldLoggerService, useExisting: NewLoggerService}]

使用第二个服务提供商

constructor(private oldLoggerService: OldLoggerService)

代码解析

5、

在讲解下一种服务提供商之前,我们现在了解一下这个类(因为下一种服务提供商需要用到它),它是用来手动创建DI令牌的!下面通过例子来详细了解一下

1)、新建一个项目,取名test--

ng new test-teaching-provider

并cd进这个文件目录

2)、新建一个名叫.ts的文件,内容如下

import { InjectionToken } from "@angular/core";export const MY_DI_TOKEN = new InjectionToken('test useVaule');

现在我们就有了一个名叫的DI令牌,那么,这个令牌的使用我将和下一小节()一起讲解

6、服务提供商

你也可以叫它值提供商,在上一章的心法篇,我也说过,服务有很多种类,现在,我们利用就来提供一个类型的服务(连接上一小节)

男妓提供什么服务_蓝讯网络服务提供_

在上一小节中我们创建了一个名叫的DI令牌,现在来使用它,代码如下

1)、新建一个名叫test--的项目

ng new test-teaching-privider

并cd进该文件目录

2)、启动应用

ng serve -o

现在你的应用应该是这个样子的

现在我们来使用来更改标题(红色框中的内容)

3)、修改的内容如下

import { Component, Inject } from '@angular/core';
import { MY_DI_TOKEN } from './assist';@Component({selector: 'app-root',templateUrl: './app.component.html',styleUrls: ['./app.component.css'],providers: [{ provide: MY_DI_TOKEN, useValue: 'test useValue' }] // 注册值提供商
})
export class AppComponent {title = 'test-teaching-provider';constructor(@Inject(MY_DI_TOKEN) myTitle: string) {// 使用值提供商this.title = myTitle;}}

现在你的界面应该变成了这样

是不是和代码中的这个字符串一样啊

代码解析

7、服务提供商

现在有这样一个场景:你新建了一个名叫hero-..ts的服务文件,而它的内容如下

import { Injectable } from '@angular/core';
import { LoggerService } from './logger.service';@Injectable({providedIn: 'root'
})
export class HeroDetailService {constructor(private loggerService: LoggerService,private auth: boolean) { }getStr() {return 'test useFactory successfully and ' + this.loggerService.getLog();}
}

注意,其中是一个服务类(也就是在服务类中使用其他服务,我前面也说过,和在组件中使用服务的方式是一样的),现在的问题是:这个服务的构造函数中多了另外一个类型的参数,那么,如果是你,你会怎样正确使用该服务,(学到这里,我想大多数人会按照如下的步骤进行),为了清晰起见,我们从头开始

1)、新建项目名叫test--,并cd进该项目

ng new test-teaching-provider

2)、新建一个名叫的服务

ng generate service logger

其内容如下

import { Injectable } from '@angular/core';@Injectable({providedIn: 'root'
})
export class LoggerService {constructor() { }getLog() {return 'use LoggerService in HeroDetailService';}
}

可以看出,这个服务类的作用是为了说明如果在服务中使用另外一个服务

3)、再新建一个名叫hero-的服务

ng generate service hero-detail

修改其内容如下

import { Injectable } from '@angular/core';
import { LoggerService } from './logger.service';@Injectable({providedIn: 'root'
})
export class HeroDetailService {constructor(private loggerService: LoggerService,private auth: boolean) { }getStr() {return 'test useFactory successfully and ' + this.loggerService.getLog();}
}

可以发现,这个服务类我是为了测试,如果测试成功,那么期望的结果是界面显示:test in

4)、删除.html默认内容,修改为一下内容

{{ str }}

5)、修改.ts文件内容为

import { Component, Inject, OnInit } from '@angular/core';
import { HeroDetailService } from './hero-detail.service';@Component({selector: 'app-root',templateUrl: './app.component.html',styleUrls: ['./app.component.css'],providers: [HeroDetailService] // 注册组件级别的服务提供商
})
export class AppComponent implements OnInit {title = 'test-teaching-provider';str: stringconstructor(private heroDetailService: HeroDetailService) {// 注入HeroDetailService}ngOnInit() {this.str = this.heroDetailService.getStr();}}

现在,你应该可以启动应用,如果不出意外的话,应该是期望的结果,可是,意外就此发生,浏览器的调试界面出现了下面的错误

(No for ),可能你也想到了,问题就出在砸门新增的上面,没错,不知道你是否还记得(我在这一章心法篇讲过的一句话)

现在你应该恍然大悟,看到的构造函数的两个参数

这时,你应该想到一种更正的方法,参见服务提供商这一小节,好,现在我们就来改一改

修改步骤如下

1)、新建.ts文件,内容如下

import { InjectionToken } from "@angular/core";export const MY_DI_TOKEN = new InjectionToken('');

2)、修改的内容如下

import { Injectable, Inject } from '@angular/core';
import { LoggerService } from './logger.service';
import { MY_DI_TOKEN } from './assist';@Injectable({providedIn: 'root'
})
export class HeroDetailService {constructor(private loggerService: LoggerService,@Inject(MY_DI_TOKEN) private auth: boolean) { }getStr() {return 'test useFactory successfully and ' + this.loggerService.getLog();}
}

3)、还有一步,别忘了为注册服务提供商(我们在.ts中为其注册)

providers: [HeroDetailService, { provide: MY_DI_TOKEN, useValue: true }] // 注册组件级别的服务提供商

现在,你的界面应该出现了期望的结果

如果你能自己做到这一步,说明前面的知识你已经掌握的足够好了!!

那么,你可能会问了,讲了这么多,额。。。。好像还没有涉及到。。。是的,接下来我们用一种更好的方式解决上面问题——,工厂函数,前面我应该也说过,我们可以直接提供一个服务实例,而不需要帮我们new,回到该项目修改以前(也就是报错的时候,我们不使用来解决此问题)使用的步骤如下

1)、新建一个.ts文件,内容如下

import { LoggerService } from "./logger.service";
import { HeroDetailService } from "./hero-detail.service";export const factoryFun = (loggerService: LoggerService)=>{return new HeroDetailService(loggerService, true);
}

可以发现函数(注意,这里是箭头函数,不能使普通的js函数,具体原因我也不太清楚。。。不好意思,原来是电脑的问题,电脑抽风了)返回一个的实例,

2)、修改.ts文件,使用该工厂函数

    providers: [HeroDetailService, {provide: HeroDetailService, useFactory: factoryFun, deps:[LoggerService]}] // 注册组件级别的服务提供商

注意如下几点

现在,期望的结果又出现了

其实,在实际应用中,不会这样使用提供商,在这里我只是为了说明的使用方法,更好的例子见官方教程:

8、类接口

还有一个很重要的知识点——类接口,在中,类接口指的是:用作DI令牌的抽象类,因为本片教程已经很长了,就不在详细讲解了,请直接看官方教程:类-接口

问题篇

不知道你现在有没有清楚下面三者的关系

[provide: a, _: b] // 其中_表示我并不关心它的值(他可能是useClass/useValue/useExisting/useFactory中的某一个)constructor(private c: a){ }

也就是a、b、c三者的关系,如果你觉得自己清楚了,那么请告诉我,下面代码期望的结果是什么?

1)、内容如下

import { Injectable } from '@angular/core';@Injectable({providedIn: 'root'
})
export class LoggerService {constructor() { }getLog() {return 'logger';}
}

2)、内容如下

import { Injectable, Inject } from '@angular/core';@Injectable({providedIn: 'root'
})
export class HeroDetailService {constructor() { }getLog() {return 'heroDetail';}
}

3)、.ts的内容如下

import { Component, OnInit } from '@angular/core';
import { HeroDetailService } from './hero-detail.service';
import { LoggerService } from './logger.service';@Component({selector: 'app-root',templateUrl: './app.component.html',styleUrls: ['./app.component.css'],providers: [{provide: HeroDetailService, useClass: LoggerService}] // 注册组件级别的服务提供商
})
export class AppComponent implements OnInit {title = 'test-teaching-provider';str: stringconstructor(private heroDetailService: HeroDetailService) {// 注入HeroDetailService}ngOnInit() {this.str = this.heroDetailService.getLog();}}

现在你来告诉我,str的值是多少?是,还是(如果不知道就先试一试)

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了