当在Angular CLI中生成服务时,它会为Injectable装饰器添加一个'provided in'属性(默认值为'root')的额外元数据。
@Injectable({
providedIn: 'root',
})
providedIn到底做什么?我假设这是使服务可用的像一个“全局”类型的单例服务的整个应用程序,然而,不会更干净地在AppModule的提供者数组中声明这样的服务?
当在Angular CLI中生成服务时,它会为Injectable装饰器添加一个'provided in'属性(默认值为'root')的额外元数据。
@Injectable({
providedIn: 'root',
})
providedIn到底做什么?我假设这是使服务可用的像一个“全局”类型的单例服务的整个应用程序,然而,不会更干净地在AppModule的提供者数组中声明这样的服务?
当前回答
根据文档:
在@Injectable()元数据中注册提供者也是允许的 Angular通过从编译后的 应用程序,如果它没有使用。
其他回答
从文档
什么是可注入装饰器?
将一个类标记为可用于Injector创建。
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class UserService {
}
服务本身是CLI生成的一个类,并使用@Injectable()进行装饰。
providedIn到底做什么?
通过将可注入对象与@NgModule或其他InjectorType关联,或者指定该可注入对象应该在“根”注入器中提供,这将是大多数应用程序中的应用级注入器。
providedIn: Type<any> | 'root' | null
提供:“根”
当你在根级提供服务时,Angular会创建一个单独的、共享的服务实例,并将它注入到任何需要它的类中。在@Injectable()元数据中注册提供商还可以让Angular通过在编译后的应用中删除不使用的服务来优化应用。
提供:模块
也可以在特定的@NgModule中指定一个服务。例如,如果您不希望某个服务对应用程序可用,除非它们导入您创建的模块,您可以指定该服务应该在模块中提供
import { Injectable } from '@angular/core';
import { UserModule } from './user.module';
@Injectable({
providedIn: UserModule,
})
export class UserService {
}
这种方法是首选的,因为如果没有注入服务,它可以对服务进行摇树(摇树是构建过程中的一个步骤,从代码库中删除未使用的代码)。
如果不能在服务中指定应该由哪个模块提供该服务,你也可以在模块中声明该服务的提供者:
import { NgModule } from '@angular/core';
import { UserService } from './user.service';
@NgModule({
providers: [UserService],
})
export class UserModule {
}
简单. .
providedIn:'root'为整个应用程序创建了一个实例,而不需要从任何NgModule中提供它。只需通过@Injectable装饰器在服务中声明即可。
如果您希望为任何组件拥有该服务的一个新实例,那么可以通过组件的提供程序声明它。这将为该组件及其子组件(如果有的话)创建另一个新实例。因此,您可以有一个具有全局作用域的实例和一个组件的另一个实例。
自Angular 6以来,providedIn: 'root'是最简单、最有效的提供服务的方法:
该服务将作为单例在整个应用范围内可用,不需要将其添加到模块的providers数组中(如Angular <= 5)。 如果服务只在一个惰性加载的模块中使用,那么该模块也会被惰性加载 如果它从未被使用过,它将不会包含在构建中(摇树)。
欲了解更多信息,请阅读文档和NgModule faq
Btw:
如果你不想要应用范围的单例,可以使用组件的提供者数组。 如果你想限制作用域,让其他开发人员无法在特定模块之外使用你的服务,可以使用NgModule的providers数组。
@Nipuna的精彩解释,
我想通过添加例子来扩展它。
如果你只使用Injectable装饰器而不使用providedin属性,比如,
@Injectable()
那么你必须在相应模块的providers数组中写入服务的名称。
像这样;
data.service.ts↴
import { Injectable } from '@angular/core';
@Injectable()
export class DataService {
constructor() {}
// Code . . .
}
app.module.ts↴
import { AppComponent } from './app.component';
import { DataService } from './core/data.service';
@NgModule({
declarations: [AppComponent],
providers: [DataService], // ⟵ LOOK HERE WE PROVIDED IT
imports: [...],
bootstrap: [AppComponent],
})
export class AppModule {}
但是,如果你使用providedIn: 'root',就像这样:
data.service.ts↴
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class DataService {
constructor() {}
// Code . . .
}
然后我们的模块看起来像这样:
app.module.ts↴
import { AppComponent } from './app.component';
import { DataService } from './core/data.service';
@NgModule({
declarations: [AppComponent],
providers: [],
imports: [...],
bootstrap: [AppComponent],
})
export class AppModule {}
看,这次我没有在providers数组中添加DataService,因为它不需要。
良好的实践
在Angular指南中,这可能会派上用场
Do provide a service with the app root injector in the @Injectable decorator of the service. Why? The Angular injector is hierarchical. Why? When you provide the service to a root injector, that instance of the service is shared and available in every class that needs the service. This is ideal when a service is sharing methods or state. Why? When you register a service in the @Injectable decorator of the service, optimization tools such as those used by the Angular CLI's production builds can perform tree shaking and remove services that aren't used by your app. Why? This is not ideal when two different components need different instances of a service. In this scenario it would be better to provide the service at the component level that needs the new and separate instance.
根据文档:
在@Injectable()元数据中注册提供者也是允许的 Angular通过从编译后的 应用程序,如果它没有使用。