非常教程

AngularJS参考手册

Angular 模块

服务提供商

前提条件:

  • 对引导有基本的了解。
  • 熟悉常用模块。

要想查看本页提到的这个带有特性模块的范例应用,参见 在线例子 / 下载范例。


提供商就相当于说明书,用来指导 DI 系统该如何获取某个依赖的值。 大多数情况下,这些依赖就是你要创建和提供的那些服务。

提供服务

如果你是用 CLI 创建的应用,那么可以使用下列 CLI 命令在项目根目录下创建一个服务。把其中的 User 替换成你的服务名。

content_copyng generate service User

该命令会创建下列 UserService 骨架:

src/app/user.service.0.ts

content_copyimport { Injectable } from '@angular/core';

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

现在,你就可以在应用中到处注入 UserService 了。

该服务本身是 CLI 创建的一个类,并且加上了 @Injectable 装饰器。默认情况下,该装饰器是用 providedIn 属性进行配置的,它会为该服务创建一个提供商。在这个例子中,providedIn: 'root' 指定该服务应该在根注入器中提供。

提供商的作用域

当你把服务提供商添加到应用的根注入器中时,它就在整个应用程序中可用了。 另外,这些服务提供商也同样对整个应用中的类是可用的 —— 只要它们有供查找用的服务令牌。

你应该始终在根注入器中提供这些服务 —— 除非你希望该服务只有在消费方要导入特定的 @NgModule 时才生效。

providedIn 与 NgModule

也可以规定某个服务只有在特定的 @NgModule 中提供。比如,如果你你希望只有当消费方导入了你创建的 UserModule 时才让 UserService 在应用中生效,那就可以指定该服务要在该模块中提供:

src/app/user.service.1.ts

content_copyimport { Injectable } from '@angular/core';
import { UserModule } from './user.module';

@Injectable({
  providedIn: UserModule,
})
export class UserService {
}

上面的例子展示的就是在模块中提供服务的首选方式。之所以推荐该方式,是因为当没有人注入它时,该服务就可以被摇树优化掉。如果没办法指定哪个模块该提供这个服务,你也可以在那个模块中为该服务声明一个提供商:

src/app/user.module.ts

content_copyimport { NgModule } from '@angular/core';

import { UserService } from './user.service';

@NgModule({
  providers: [UserService],
})
export class UserModule {
}

使用惰性加载模块限制提供商的作用域

在 CLI 生成的基本应用中,模块是立即加载的,这意味着它们都是由本应用启动的,Angular 会使用一个依赖注入体系来让一切服务都在模块间有效。对于立即加载式应用,应用中的根注入器会让所有服务提供商都对整个应用有效。

当使用惰性加载时,这种行为需要进行改变。惰性加载就是只有当需要时才加载模块,比如路由中。它们没办法像立即加载模块那样进行加载。这意味着,在它们的 providers 数组中列出的服务都是不可用的,因为根注入器并不知道这些模块。

当 Angular 的路由器惰性加载一个模块时,它会创建一个新的注入器。这个注入器是应用的根注入器的一个子注入器。想象一棵注入器树,它有唯一的根注入器,而每一个惰性加载模块都有一个自己的子注入器。路由器会把根注入器中的所有提供商添加到子注入器中。如果路由器在惰性加载时创建组件, Angular 会更倾向于使用从这些提供商中创建的服务实例,而不是来自应用的根注入器的服务实例。

任何在惰性加载模块的上下文中创建的组件(比如路由导航),都会获取该服务的局部实例,而不是应用的根注入器中的实例。而外部模块中的组件,仍然会收到来自于应用的根注入器创建的实例。

虽然你可以使用惰性加载模块来提供实例,但不是所有的服务都能惰性加载。比如,像路由之类的模块只能在根模块中使用。路由器需要使用浏览器中的全局对象 location 进行工作。

使用组件限定服务提供商的作用域

另一种限定提供商作用域的方式是把要限定的服务添加到组件的 providers 数组中。组件中的提供商和 NgModule 中的提供商是彼此独立的。 当你要立即加载一个自带了全部所需服务的模块时,这种方式是有帮助的。 在组件中提供服务,会限定该服务只能在该组件中有效(同一模块中的其它组件不能访问它)。

src/app/app.component.ts

content_copy@Component({
/* . . . */
  providers: [UserService]
})

在模块中提供服务还是在组件中?

通常,要在根模块中提供整个应用都需要的服务,在惰性加载模块中提供限定范围的服务。

路由器工作在根级,所以如果你把服务提供商放进组件(即使是 AppComponent)中,那些依赖于路由器的惰性加载模块,将无法看到它们。

当你必须把一个服务实例的作用域限定到组件及其组件树中时,可以使用组件注册一个服务提供商。 比如,用户编辑组件 UserEditorComponent,它需要一个缓存 UserService 实例,那就应该把 UserService 注册进 UserEditorComponent 中。 然后,每个 UserEditorComponent 的实例都会获取它自己的缓存服务实例。


关于 NgModule 的更多知识

你还可能对下列内容感兴趣:

  • 单例服务详细解释了本页包含的那些概念。
  • 惰性加载模块。
  • 可摇树优化的服务提供商。
  • NgModule 常见问题。
AngularJS

Angular 是一个开发平台。它能帮你更轻松的构建 Web 应用。Angular 集声明式模板、依赖注入、端到端工具和一些最佳实践于一身,为你解决开发方面的各种挑战。

AngularJS目录

1.快速上手 | quick start
2.语言服务
3.安全
4.环境准备与部署
5.Service Worker
6.保持最新
7.从 AngularJS 升级
8.服务端渲染
9.Visual Studio 2015 快速上手
10.风格指南
11.国际化
12.测试
13.路由与导航
14. 教程 | Tutorial
15.架构
16.组件与模板
17.表单
18.可观察对象与RxJS
19.引导启动
20.Angular 模块
21.依赖注入
22.HttpClient
23.词汇表
24.AngularJS 应用
25.AngularJS 模块
26.AngularJS 事件
27.AngularJS HTML DOM
28.AngularJS 过滤器
29.AngularJS 控制器
30.AngularJS 指令
31.AngularJS 表达式
32.AngularJS 简介
33.AngularJS 参考手册
34.AngularJS 实例
35.AngularJS 输入验证
36.AngularJS 表单
37.AngularJS SQL
38.AngularJS 表格
39.AngularJS Http
40.AngularJS 包含
41.AngularJS Bootstrap
42.AngularJS API
43.AngularJS ng-checked 指令
44.AngularJS ng-change 指令
45.AngularJS ng-blur 指令
46.AngularJS ng-bind-template 指令
47.AngularJS ng-bind-html 指令
48.AngularJS ng-bind 指令
49.AngularJS ng-app 指令
50.AngularJS Scope(作用域)
51.AngularJS ng-model 指令
52.AngularJS ng-dblclick 指令
53.AngularJS ng-cut 指令
54.AngularJS ng-csp 指令
55.AngularJS ng-copy 指令
56.AngularJS ng-controller 指令
57.AngularJS ng-cloak 指令
58.AngularJS ng-click 指令
59.AngularJS ng-class-odd 指令
60.AngularJS ng-class-even 指令
61.AngularJS ng-class 指令
62.AngularJS ng-keyup 指令
63.AngularJS ng-keypress 指令
64.AngularJS ng-keydown 指令
65.AngularJS ng-init 指令
66.AngularJS ng-include 指令
67.AngularJS ng-if 指令
68.AngularJS ng-href 指令
69.AngularJS ng-hide 指令
70.AngularJS ng-focus 指令
71.AngularJS ng-disabled 指令
72.AngularJS ng-non-bindable 指令
73.AngularJS ng-mouseup 指令
74.AngularJS ng-mouseover 指令
75.AngularJS ng-mousemove 指令
76.AngularJS ng-mouseleave 指令
77.AngularJS ng-mouseenter 指令
78.AngularJS ng-mousedown 指令
79.AngularJS ng-model-options 指令
80.AngularJS ng-model 指令
81.AngularJS ng-list 指令
82.AngularJS ng-style 指令
83.AngularJS ng-srcset 指令
84.AngularJS ng-src 指令
85.AngularJS ng-show 指令
86.AngularJS ng-selected 指令
87.AngularJS ng-repeat 指令
88.AngularJS ng-readonly 指令
89.AngularJS ng-paste 指令
90.AngularJS ng-options 指令
91.AngularJS ng-open 指令
92.AngularJS ng-value 指令
93.AngularJS ng-switch 指令
94.AngularJS ng-submit 指令
95.AngularJS 服务(Service)
96.AngularJS Select(选择框)
97.AngularJS 动画
98.AngularJS 依赖注入