Angular service and 依赖注入

Master Angular service and 依赖注入mechanism, implementationcomponent间 data共享 and 逻辑复用

Angular service

service is Angular applicationin用于encapsulation可复用逻辑, data and functions class, 它们可以被 many 个component共享 and using.

提示

service 主要作用 is implementationcomponent间 data共享 and 逻辑复用, 避免 in componentinwriting重复code.

1. creationservice

可以using Angular CLI creationservice:

ng generate service user

1.1 service basicstructure

// user.service.ts
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root' // serviceregister方式
})
export class UserService {
  private users = [
    { id: 1, name: '张三', age: 25 },
    { id: 2, name: '李四', age: 30 },
    { id: 3, name: '王五', age: 35 }
  ];

  constructor() { }

  getUsers() {
    return this.users;
  }

  getUserById(id: number) {
    return this.users.find(user => user.id === id);
  }

  addUser(user: { name: string, age: number }) {
    const newUser = {
      id: this.users.length + 1,
      ...user
    };
    this.users.push(newUser);
    return newUser;
  }
}

2. 依赖注入

依赖注入 (DI) is Angular coremechanism之一, 它允许将service注入 to component or otherserviceinusing.

2.1 in componentinusingservice

// user.component.ts
import { Component, OnInit } from '@angular/core';
import { UserService } from '../user.service';

@Component({
  selector: 'app-user',
  templateUrl: './user.component.html',
  styleUrls: ['./user.component.css']
})
export class UserComponent implements OnInit {
  users: any[] = [];

  // throughconstructfunction注入service
  constructor(private userService: UserService) { }

  ngOnInit(): void {
    // usingservicemethod获取data
    this.users = this.userService.getUsers();
  }

  addUser() {
    const newUser = this.userService.addUser({ name: '赵六', age: 40 });
    console.log(' new 增user: ', newUser);
  }
}

3. service register方式

Angular providing了 many 种serviceregister方式, 决定了service 作用域 and 生命周期.

3.1 根级register

using providedIn: 'root' 将serviceregister to 根注入器, 整个application共享一个serviceinstance:

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

3.2 module级register

in module providers arrayinregisterservice, 该module及其子module共享一个serviceinstance:

// app.module.ts
import { UserService } from './user.service';

@NgModule({
  declarations: [
    // component声明
  ],
  imports: [
    // moduleimport
  ],
  providers: [UserService], // module级register
  bootstrap: [AppComponent]
})
export class AppModule { }

3.3 component级register

in component providers arrayinregisterservice, 每个componentinstance都会creation一个 new serviceinstance:

@Component({
  selector: 'app-user',
  templateUrl: './user.component.html',
  styleUrls: ['./user.component.css'],
  providers: [UserService] // component级register
})
export class UserComponent {
  // componentcode
}

4. service inheritance and 依赖

service可以inheritanceotherservice, 也可以依赖otherservice:

// base.service.ts
@Injectable({
  providedIn: 'root'
})
export class BaseService {
  protected baseUrl = 'https://api.example.com';
  
  constructor() { }
}

// user.service.ts
@Injectable({
  providedIn: 'root'
})
export class UserService extends BaseService {
  constructor(private http: HttpClient) { // 依赖 HttpClient service
    super(); // 调用父classconstructfunction
  }
  
  getUser() {
    return this.http.get(`${this.baseUrl}/users`);
  }
}

5. HTTP service

Angular providing了 HttpClient service用于发送 HTTP request:

注意

using HttpClient 需要先import HttpClientModule module.

// app.module.ts
import { HttpClientModule } from '@angular/common/http';

@NgModule({
  imports: [
    BrowserModule,
    HttpClientModule // import HttpClientModule
  ],
  // ...
})
export class AppModule { }

// user.service.ts
import { HttpClient } from '@angular/common/http';

@Injectable({
  providedIn: 'root'
})
export class UserService {
  constructor(private http: HttpClient) { }
  
  getUsers() {
    return this.http.get('https://jsonplaceholder.typicode.com/users');
  }
  
  getUserById(id: number) {
    return this.http.get(`https://jsonplaceholder.typicode.com/users/${id}`);
  }
}

// user.component.ts
export class UserComponent implements OnInit {
  users: any[] = [];
  error: string = '';
  
  constructor(private userService: UserService) { }
  
  ngOnInit(): void {
    this.userService.getUsers()
      .subscribe({
        next: (data) => this.users = data,
        error: (err) => this.error = err.message
      });
  }
}

6. service best practices

  1. service应该遵循单一职责principles, 每个service只负责一个specific functions
  2. 优先using providedIn: 'root' registerservice, 简化service management
  3. 避免 in serviceinstorecomponentspecific status, status应该由component自己management or usingstatusmanagementlibrary
  4. service应该 is 无status , or 者只package含application级 共享status
  5. usinginterface定义service 契约, improvingcode 可test性 and 可maintenance性

依赖注入 advanced features

1. 可选依赖

可以using @Optional 装饰器标记可选依赖:

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

constructor(@Optional() private optionalService: OptionalService) {
  if (this.optionalService) {
    // using可选service
  }
}

2. 依赖标记

可以using @Inject 装饰器注入specific 依赖:

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

const API_URL = new InjectionToken<string>('apiUrl');

//  in moduleinproviding值
@NgModule({
  providers: [
    { provide: API_URL, useValue: 'https://api.example.com' }
  ]
})
export class AppModule { }

//  in servicein注入值
constructor(@Inject(API_URL) private apiUrl: string) {
  console.log('API URL:', this.apiUrl);
}

练习 1: creation and usingservice

  1. using Angular CLI creation一个名 for product service
  2. in serviceinimplementation产品data 增删改查functions
  3. creation一个产品component, 注入并using该service
  4. in componentin显示产品list, 并implementation添加 new 产品 functions

练习 2: using HTTP service

  1. creation一个名 for post service, using HttpClient 调用 JSONPlaceholder API
  2. implementation获取帖子list and 单个帖子 method
  3. creation一个帖子component, 显示帖子list
  4. 添加errorprocessing and 加载status