配置providedIn: ‘root‘ 的angular service 不一定在整个application 层面就是单例服务

There are two ways to make a service a singleton in Angular:

  • Set the providedIn property of the @Injectable() to “root”.
  • Include the service in the AppModule or in a module that is only imported by the AppModule

以上是Angular 官网上的原话,说是有两种方法在Angular 应用中提供单例服务,一个是对于可注入的服务配置providedIn: 'root', 二个是只在AppModule 里面引入服务或者只在AppModule 里面引入提供服务的模块。

所以使用示例中完整代码, 发现了不能理解的问题,问题总结下来就是就算配置providedIn: 'root‘, 貌似服务也不是单例的,不管是急性还是惰性加载模块,还需要看看是否在component 里面再次定义了providers。如有问题,欢迎大家指正讨论!

具体执行过程如下:
在这里插入图片描述
app.module.ts 代码如下:

@NgModule({
  imports: [
    BrowserModule,
    ContactModule,
    DevicesModule,
    GreetingModule,  // 注释掉了完整代码中GreetingModule.forRoot 方法的定义
    AppRoutingModule
  ],
  declarations: [
    AppComponent
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.component.ts 代码如下:

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    <app-greeting></app-greeting>
    <nav>
      <a routerLink="devices" routerLinkActive="active">Devices</a>
      <a routerLink="contact" routerLinkActive="active">Contact</a>
      <a routerLink="items" routerLinkActive="active">Items</a>
      <a routerLink="customers" routerLinkActive="active">Customers</a>
    </nav>
    <router-outlet></router-outlet>
  `
})
export class AppComponent {
}

其中Device 和Contact 是急性加载模块,Items 和Customers 是惰性加载模块。
导航下方的形如times 2’s 为注入的UserService.username

user.service.ts 中配置了providedIn: 'root', 需要注意这个是一个重要的配置,这个告知Angular在应用层面提供服务。

import { Injectable, Optional } from '@angular/core';

let nextId = 1;

export class UserServiceConfig {
  userName = 'Philip Marlowe';
}

@Injectable({providedIn: 'root'})
export class UserService {
  id = nextId++;
  
  constructor(@Optional() config?: UserServiceConfig) {
    console.log('user service constructor', config, this.id,);
    if (config) { this._userName = config.userName; }
  }

  get userName() {
    // Demo: add a suffix if this service has been created more than once
    const suffix = this.id > 1 ? ` times ${this.id}` : '';
    return this._userName + suffix;
  }
  private _userName = 'Sherlock Holmes';
}

分别点击Device 和Items, 渲染出来的都是包含Sherlock Holmes times 3's Devices,说明点击Device 的时候重新生成了一个新的UserService实例,并且Items 和 Device 使用的是同一个UserService实例。Device 和Items 相同的配置都是在构造函数中直接引用UserService, 形如:

import { Component } from '@angular/core';
import { UserService } from '../greeting/user.service';

@Component({
  selector: 'app-devices',
  template: `<h2>{{userName}}'s Devices</h2>`,
})
export class DevicesComponent {
  userName = '';

  constructor(private userService: UserService) {
    this.userName = userService.userName;
  }
}

分别点击Contact 和 Customer, 渲染出来的都是Sherlock Holmes times N's, 其中N 是不断上涨的,说明不管点击Contact 还是Customer 都会重新生成新的UserService 实例,而且这俩模块的UserService实例是相互隔离的。Contact和Customer 模块相同的配置都是在@Component装饰器中配置了Providers: [UserService]

import { Component, OnInit } from '@angular/core';
import { FormBuilder, Validators } from '@angular/forms';

import { Contact, ContactService } from './contact.service';
import { UserService } from '../greeting/user.service';

@Component({
  selector: 'app-contact',
  template: `<h2>{{userName}}'s Contacts</h2>`,
  styleUrls: [ './contact.component.css' ],
  providers: [UserService]
})
export class ContactComponent implements OnInit {
  userName = '';

  constructor(private contactService: ContactService, userService: UserService) {
    this.userName = userService.userName;
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值