MST

星途 面试题库

面试题:Angular服务的最佳实践及在大型项目中的架构优化

在一个大型的Angular项目中,有众多的服务。请阐述如何基于服务的功能进行合理的模块划分与架构设计,以提高代码的可维护性、可扩展性。同时,说明如何使用Angular的特性(如懒加载模块、依赖注入的高级特性等)来优化服务的调用性能,减少应用的加载时间,提供一些具体的策略和示例。
12.6万 热度难度
前端开发Angular

知识考点

AI 面试

面试题答案

一键面试

基于服务功能的模块划分与架构设计

  1. 按业务功能划分模块
    • 将相关的服务归为同一个模块,例如用户管理相关的服务(如用户登录、注册、信息更新等服务)可以放在 user - module 中。这样当需要修改或扩展用户相关功能时,所有相关代码都集中在一个模块,方便维护和查找。
    • 示例:
// user - module.ts
import { NgModule } from '@angular/core';
import { UserLoginService } from './user - login.service';
import { UserRegisterService } from './user - register.service';

@NgModule({
  providers: [UserLoginService, UserRegisterService]
})
export class UserModule {}
  1. 共享模块
    • 对于一些通用的服务,如日志记录、网络请求等服务,可以创建一个共享模块 shared - module。这样多个业务模块都可以复用这些服务,避免代码重复。
    • 示例:
// shared - module.ts
import { NgModule } from '@angular/core';
import { LoggerService } from './logger.service';
import { HttpService } from './http.service';

@NgModule({
  providers: [LoggerService, HttpService],
  exports: []
})
export class SharedModule {}
  1. 功能隔离
    • 确保每个模块的服务功能相对独立,减少模块之间的耦合。比如,订单模块的服务不应该直接依赖于库存模块的内部实现细节,而应该通过定义良好的接口进行交互。
    • 示例:
// order - module.ts
import { NgModule } from '@angular/core';
import { OrderService } from './order.service';
import { InventoryService } from '../inventory/inventory.service';

// OrderService 通过接口使用 InventoryService 的功能
export interface InventoryInterface {
  checkStock(productId: number): boolean;
}

@NgModule({
  providers: [OrderService]
})
export class OrderModule {}

使用 Angular 特性优化服务调用性能与加载时间

  1. 懒加载模块
    • 策略:将不常用或较大的模块设置为懒加载。这样在应用启动时,这些模块不会立即加载,只有在需要时才会加载,从而减少初始加载时间。
    • 示例
      • app - routing.module.ts 中配置懒加载模块:
const routes: Routes = [
  {
    path: 'admin',
    loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule)
  }
];
- 这里 `admin` 模块是懒加载的,当用户访问 `/admin` 路由时,`AdminModule` 及其相关的服务才会被加载。

2. 依赖注入的高级特性 - 使用 @Injectable({ providedIn: 'root' }): - 策略:对于一些全局单例的服务,可以在服务类上使用 @Injectable({ providedIn: 'root' }) 语法糖。这样 Angular 会在根模块自动提供该服务,并且保证整个应用中只有一个实例,避免重复创建服务实例带来的性能开销。 - 示例

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

@Injectable({
  providedIn: 'root'
})
export class GlobalConfigService {
  private config: any;
  constructor() {
    // 初始化配置
    this.config = { apiUrl: 'https://example.com/api' };
  }
  getConfig() {
    return this.config;
  }
}
- **依赖注入工厂函数**:
  - **策略**:当服务的创建需要复杂逻辑或者依赖于其他服务时,可以使用依赖注入工厂函数。这样可以在创建服务实例时,根据具体需求进行定制化创建,同时也可以控制服务的创建时机,提高性能。
  - **示例**:
import { Injectable, Inject, InjectionToken } from '@angular/core';

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

export function httpServiceFactory(apiUrl: string) {
  return new HttpService(apiUrl);
}

@Injectable()
export class HttpService {
  constructor(private apiUrl: string) {}
  get(url: string) {
    // 实际的网络请求逻辑
    return fetch(this.apiUrl + url);
  }
}

@NgModule({
  providers: [
    {
      provide: HttpService,
      useFactory: httpServiceFactory,
      deps: [API_URL]
    },
    { provide: API_URL, useValue: 'https://example.com/api' }
  ]
})
export class AppModule {}
- 这里通过工厂函数 `httpServiceFactory` 创建 `HttpService`,并且可以灵活配置 `API_URL`。