如何在Angular 2中创build一个单例服务?
我已经读过注入引导应该有所有的孩子共享相同的实例,但我的主要和头组件(主要应用程序包括头部组件和路由器出口)每个获得我的服务单独的实例。
我有一个FacebookService,我用来调用Facebook的JavaScript API和使用FacebookService的UserService。 这是我的引导:
bootstrap(MainAppComponent, [ROUTER_PROVIDERS, UserService, FacebookService]);
从我的日志logging看起来像bootstrap调用完成,然后我看到FacebookService,然后在每个构造函数代码运行,MainAppComponent,HeaderComponent和DefaultComponent之前创buildUserService:
杰森是完全正确的! 这是由dependency injection的工作方式造成的。 它基于分级注射器。
Angular2应用程序中有几个注入器:
- 引导应用程序时configuration的根目录
- 每个组件的注射器。 如果您在另一个组件内使用组件。 组件注入器是父组件的子组件。 应用程序组件(您在指定应用程序时指定的组件)具有根注入器作为父注入器)。
当Angular2试图在组件构造函数中注入某些东西时:
- 它查看与组件相关的注入器。 如果有匹配的,就用它来获取相应的实例。 这个实例是懒洋洋地创build的,并且是这个注入器的一个单例。
- 如果这个级别没有提供者,它将查看父级注入器(依此类推)。
因此,如果您想为整个应用程序提供单例,则需要在根注入器或应用程序组件注入器级别定义提供程序。
但是Angular2会从底部看注射器树。 这意味着将使用最低级别的提供者,并且关联实例的范围将是这个级别。
看到这个问题的更多细节:
- 将angular色2(testing版)中的服务注入另一个服务的最佳方式是什么?
如果您在bootstrap()
列出提供bootstrap()
,则不需要在组件装饰器中列出它们:
@Component({ selector: 'main-app', templateUrl: '/views/main-app.html', directives: [ROUTER_DIRECTIVES, HeaderComponent], // DO NOT LIST PROVIDERS HERE IF THEY ARE IN bootstrap()! // (unless you want a new instance) //providers: [FacebookService, UserService] })
事实上,在“提供者”中列出你的类创build了一个新的实例,如果任何父组件已经列出,那么孩子们不需要,如果他们这样做,他们会得到一个新的实例。
更新
有了NgModule,现在我要做的就是创build一个带有你的服务类的“CoreModule”,并在模块的提供者中列出服务。 然后,将核心模块导入您的主应用程序模块中,该模块将向在其构造函数中请求该类的任何子项提供一个实例:
CoreModule.ts
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { ApiService } from './api.service'; @NgModule({ imports: [ CommonModule ], exports: [ // components that we want to make available ], declarations: [ // components for use in THIS module ], providers: [ // singleton services ApiService, ] }) export class CoreModule { }
AppModule.ts
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { AppComponent } from './app.component'; import { CoreModule } from './core/core.module'; @NgModule({ declarations: [ AppComponent ], imports: [ CommonModule, CoreModule // will provide service ], providers: [], bootstrap: [ AppComponent ] }) export class AppModule { }
我知道angular有像Thierry所说的分级注射器。
但是我还有另外一个select,以防你发现一个用户不想在父进程注入的用例。
我们可以通过创build一个服务的实例来实现,并且提供总是返回的。
import { provide, Injectable } from '@angular/core'; import { Http } from '@angular/core'; //Dummy example of dependencies @Injectable() export class YourService { private static instance: shareService = null; // Return the instance of the service public static getInstance(http: Http): YourService { if (YourService.instance === null) { YourService.instance = new YourService(http); } return YourService.instance; } constructor(private http: Http) {} } export const YOUR_SERVICE_PROVIDER = [ provide(YourService, { deps: [Http], useFactory: (http: Http): YourService => { return YourService.getInstance(http); } }) ];
然后在你的组件上使用你自定义的提供方法。
@Component({ providers: [YOUR_SERVICE_PROVIDER] })
而且你应该有一个单独的服务,而不依赖于分级注射器。
我并不是说这是一个更好的方法,只是为了防止有人有分级注射器不可能的问题。
语法已被更改。 检查这个链接
依赖性是喷油器范围内的单例。 在下面的例子中,一个HeroService实例在HeroesComponent和它的HeroListComponent子元素之间共享。
第1步。使用@Injectable装饰器创build单例类
@Injectable() export class HeroService { getHeroes() { return HEROES; } }
第2步。在构造函数中注入
export class HeroListComponent { constructor(heroService: HeroService) { this.heroes = heroService.getHeroes(); }
第3步。注册提供商
@NgModule({ imports: [ BrowserModule, FormsModule, routing, HttpModule, JsonpModule ], declarations: [ AppComponent, HeroesComponent, routedComponents ], providers: [ HeroService ], bootstrap: [ AppComponent ] }) export class AppModule { }
这里是Angular 2.3版本的一个实例。 只需像这个构造函数(private _userService:UserService)那样调用服务的构造函数即可。 它会为应用程序创build一个单身人士。
user.service.ts
import { Injectable } from '@angular/core'; import { Observable } from 'rxjs/Rx'; import { Subject } from 'rxjs/Subject'; import { User } from '../object/user'; @Injectable() export class UserService { private userChangedSource; public observableEvents; loggedUser:User; constructor() { this.userChangedSource = new Subject<any>(); this.observableEvents = this.userChangedSource.asObservable(); } userLoggedIn(user:User) { this.loggedUser = user; this.userChangedSource.next(user); } ... }
app.component.ts
import { Component } from '@angular/core'; import { Observable } from 'rxjs/Observable'; import { UserService } from '../service/user.service'; import { User } from '../object/user'; @Component({ selector: 'myApp', templateUrl: './app.component.html' }) export class AppComponent implements OnInit { loggedUser:User; constructor(private _userService:UserService) { this._userService.observableEvents.subscribe(user => { this.loggedUser = user; console.log("event triggered"); }); } ... }
将@Injectable
装饰器添加到服务中,并将其注册为根模块中的提供者将使其成为单例。
这似乎对我很好
@Injectable() export class MyStaticService { static instance: MyStaticService; constructor() { return MyStaticService.instance = MyStaticService.instance || this; } }
您可以在提供程序中使用useValue
import { MyService } from './my.service'; @NgModule({ ... providers: [ { provide: MyService, useValue: new MyService() } ], ... })