是服务还是提供者?被Angular教程所迷惑

时间:2018-08-08 23:15:40

标签: angular service dependency-injection

我目前正在其主要网站上关注Angular教程,但我对其中的概念之一感到困难。它在指代什么是服务和什么是提供者的方式上感觉很松散,我不知道它是一个还是另一个。该链接将您带到本教程的问题部分。

https://angular.io/tutorial/toh-pt4#injectable-services

据我所知,服务用于将数据提供给组件。 组件通过将服务注入到服务中来访问服务。但是,注入器本身具有某种功能,因此在注入之前必须使服务适用于该服务。

但是,我正在阅读的指南在指代什么是服务和什么是提供者的方式上感到松懈。起初,我认为整个Hero.Service.ts都是Service。然后,它说@Injectable将类标记为Service。好的,是的,这就是组件的工作方式,装饰器指定它是什么。但是指南说,

“ HeroService类将提供可注射的服务”

等等,所以HeroService不是服务,它提供了服务对象?请记住,稍后会出现“将要提供注射服务”的字样。

该指南详细介绍了服务如何检索组件的数据,然后介绍了如何通过提供程序将服务引入依赖注入程序。

这是麻烦。它说提供者创建或交付服务,在这种情况下实例化HeroService。然后它说HeroService将成为HeroService的提供者。再说一遍,这里有两行将HeroService称为服务

简单地说:“您必须使HeroService可用于依赖项注入系统,然后Angular才能将其注入HeroesComponent”。

再次隐式地“您通过注册提供者来执行此操作。提供者是可以创建或交付服务的事物;在这种情况下,它将实例化HeroService类以提供服务。”

在教程标题创建HeroService之前,“它们应着重于呈现数据并将数据访问权委派给服务...在本教程中,您将创建一个HeroService,所有应用程序类都可以使用它来获得英雄。”注意:英雄就是数据

但是,然后他们说HeroService已注册为提供者? “现在,您需要确保HeroService已注册为该服务的提供者” 如果HeroService是提供者,那么“此服务”指的是什么?

现在请记住“ HeroService类将要提供可注射服务”这一行

因此,我在本教程的两行中提到HeroService即服务,另外两行说这是Provider。除非在后一种情况下,否则他们以严格口语化的方式使用“提供”或“服务”一词,而实际上并非指提供者和服务。

3 个答案:

答案 0 :(得分:0)

简单地说:

将@Injectable注释放在您的服务上方,将可以通过依赖项注入来发现它。 @Injectable注释基本上是一个类的标志,可以在其他元素(类)的其他地方发现它。

在您的模块中,您必须将服务添加到“ provides”数组中。 实例化模块时,它将创建此服务的单个实例。因此,将您的模块视为提供者。一旦建立了这种机制,您就可以在构造器中的任何地方使用该服务(组件,其他服务等)。

答案 1 :(得分:0)

  

在指的是什么服务和什么是提供者的方式上感觉很松散,我无法确定它是一个还是另一个。

服务是应用程序中存在的JavaScript 对象,提供程序是您访问该对象方式。两者不是一回事,但是它们一起使您可以从其他地方访问您的服务。没有提供者,您将无法获得服务,而提供者需要提供一些东西。

服务只是用于描述对象实例(通常是TypeScript类)的术语。之所以将它们称为“服务”,是因为该术语通常在依赖项注入中用于描述执行单个目的的共享库。

  

“ HeroService类将提供可注射的服务”

这里的 provide 一词是指语法中的动词。不应将它与Angular用于在提供程序列表中定义 entry 的TypeScript类型Provider混淆。

一种更好的写上述句子的方法:

  

“ HeroService类将声明可注射服务”

我同意您所说的令人困惑的说法。因此,我只解释一下工作原理。

提供商

单个 provider 是实现Provider接口(实际上是多个接口)的JavaScript对象,但我的观点是,它是一个告诉Angular如何关联具有值的令牌。

只有NgModule可以在编译时定义提供程序。我们经常这样做:

@NgModule({
     providers: [HeroService]
})

现在,记住上面我曾说过 provider 是一个JavaScript对象,但是在NgModule示例中,我们没有定义对象。我们只使用HeroService,从技术上讲,它是一个构造函数。

这是为了使程序员更容易。在编译时,Angular将查看HeroService来了解元数据的相关内容,它将自动生成 provider 对象。

通过以下操作创建元数据

 @Injectable()
 export class HeroService {}

@Injectable装饰器添加了隐藏的元数据,它描述了如何创建HeroService实例。

我们可以通过自己定义提供者对象来做同样的事情,如果我们使用 provider 对象来做,则该服务不需要@Injectable装饰器,因为我们正在创建它自己。

@NgModule({
     providers: [{provide: HeroService, useValue: new HeroService()}]
})

所以我们现在可以解释为什么他们说“ HeroService类将提供可注射的服务”。这是因为HeroService使用@Injectable装饰器来声明服务的提供者。

正在注入

Angular为您做了很多工作。在编写组件时,要注入HeroService,以便可以使用它。您所要做的就是以下操作。

 @Component({....})
 export class AppComponent {
       constructor(heroService: HeroService) {
                             // ^^^ this is the provider token
       }
 }

以上方法之所以有效,是因为Angular可以推断构造函数需要哪些提供程序。它查看第一个参数,并看到类型为HeroService。我们称其为可注入的 token ,并且Angular可以搜索提供者以寻找其中具有provide: HeroService的地方。然后,它使用该提供程序获取并将其传递给构造函数。

我们可以通过以下操作打破依赖注入。

 @Component({....})
 export class AppComponent {
       constructor(heroService: any) {
                             // ^^^ this is an unknown provider
       }
 }

Angular无法再推断提供者的令牌。它不知道已声明的众多提供程序中的哪一个是程序员想要使用的提供程序。

我们可以声明我们真正想要的提供商令牌

 @Component({....})
 export class AppComponent {
       constructor(@Inject(HeroService) heroService: any) {
                        // ^^^ we declare the token manually
       }
 }

当Angular需要帮助时,我们使用@Inject装饰器手动声明应使用哪个提供者 token

单人

在Angular 6中引入了一项新功能,使您可以在根模块中将Service声明为提供程序。这是注射剂的“ providedIn”选项。

 @Injectable({ providedIn: 'root' })
 export class HeroService {}

我上面说过,@Injectable使在NgModule中的提供者数组中添加类变得更加容易。好吧,providerIn更进一步,现在为您直接将其添加到模块中。

这些事情可能会令人困惑,因为它们隐藏了依赖项注入系统正在执行的基础工作。它使更多功能看起来像魔术,而不是说明它们在做什么。

答案 2 :(得分:0)

服务只是一个打字稿类。与组件,指令等不同,它不需要任何装饰器

那么如何从组件访问服务实例?

我们可以只导入服务类并使用new关键字实例化它。但是手动实例化该类是一种不好的做法。

因此,我们现在需要研究Angular依赖注入,以了解如何从组件访问服务实例。 Angular依赖注入是一种分层注入,即,如果已经在更高级别上注入了实例,则所有子组件将自动获得对该实例的访问权限

通常,我们导入服务类,将构造函数参数中的类型与访问修饰符一起使用。这足以通知Angular组件需要访问特定服务的实例。因此,这需要在需要访问服务实例的所有组件中完成

,但是有时我们还需要在providers字段中提及服务名称。我们什么时候需要这样做?如果以下情况之一适用:

  1. 明确告诉Angular组件需要服务的新实例,即使该实例已经在更高级别中可用。
  2. 如果没有任何实例的服务实例已经注入到任何地方,即在任何父组件或根模块等中,那么我们需要在providers字段中提及服务类名称,以便Angular知道一个新实例需要创建并注入到该组件中(然后其所有子组件都可以使用)