面试题答案
一键面试Angular服务在应用架构中的作用
- 代码复用:服务允许将通用的功能逻辑封装起来,多个组件可以共享这些功能,避免在每个组件中重复编写相同的代码。例如,数据获取逻辑、用户认证逻辑等都可以放在服务中。
- 分离关注点:遵循单一职责原则,将不同功能模块划分到各自的服务中,使得组件的职责更加清晰。组件专注于处理视图相关的逻辑,而服务负责处理业务逻辑、数据访问等其他方面的逻辑。
- 管理全局状态:服务可以作为存储和管理应用全局状态的地方。例如,用户登录状态、应用配置等信息可以在服务中维护,不同组件可以通过服务获取和更新这些状态。
依赖注入的实现原理
- 容器:Angular有一个依赖注入容器,它负责创建、管理和提供依赖对象。这个容器是一个树形结构,根注入器位于顶部,每个组件也有自己的注入器,形成注入器树。
- 注册提供商:在应用的模块(NgModule)或组件中,通过
providers
数组注册服务提供商。提供商告诉注入器如何创建服务实例,例如使用class
关键字指定服务类,也可以使用工厂函数、值对象等方式。 - 解析依赖:当一个组件需要某个服务(即依赖)时,它会向自己的注入器请求该服务。注入器首先在自己的范围内查找提供商,如果找不到,则向上级注入器查找,直到在根注入器中找到或返回
null
。如果找到了提供商,注入器会根据提供商的定义创建服务实例(如果尚未创建),并将其返回给组件。
用户认证服务设计与依赖注入实现
- 创建用户认证服务
import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class AuthService { private isAuthenticated = false; public checkAuthStatus(): boolean { return this.isAuthenticated; } public login(): void { // 模拟登录逻辑 this.isAuthenticated = true; } public logout(): void { // 模拟登出逻辑 this.isAuthenticated = false; } }
@Injectable({ providedIn: 'root' })
表示该服务在根注入器中提供,保证了服务的单例性,整个应用只有一个该服务的实例。
- 在组件中使用依赖注入
import { Component } from '@angular/core'; import { AuthService } from './auth.service'; @Component({ selector: 'app - my - component', templateUrl: './my - component.html' }) export class MyComponent { constructor(private authService: AuthService) {} public checkUserAuth(): void { const isAuth = this.authService.checkAuthStatus(); console.log('User is authenticated:', isAuth); } }
- 在组件的构造函数中,通过类型声明(
private authService: AuthService
),Angular的依赖注入系统会自动将AuthService
的实例注入到组件中。
- 在组件的构造函数中,通过类型声明(
保证服务的可测试性
- 单元测试:可以使用
jest
或karma
等测试框架对AuthService
进行单元测试。在测试中,可以创建AuthService
的模拟实例,测试其方法的逻辑。import { TestBed } from '@angular/core/testing'; import { AuthService } from './auth.service'; describe('AuthService', () => { let service: AuthService; beforeEach(() => { TestBed.configureTestingModule({}); service = TestBed.inject(AuthService); }); it('should be created', () => { expect(service).toBeTruthy(); }); it('should return false for initial auth status', () => { const isAuth = service.checkAuthStatus(); expect(isAuth).toBeFalse(); }); it('should set authentication status to true after login', () => { service.login(); const isAuth = service.checkAuthStatus(); expect(isAuth).toBeTrue(); }); it('should set authentication status to false after logout', () => { service.login(); service.logout(); const isAuth = service.checkAuthStatus(); expect(isAuth).toBeFalse(); }); });
- 通过
TestBed
可以模拟Angular的依赖注入环境,方便对服务进行单元测试。
- 通过
- 组件测试:在测试使用
AuthService
的组件时,可以使用Mock
对象来替换真实的AuthService
,这样可以控制服务的行为,便于测试组件在不同认证状态下的表现。import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MyComponent } from './my - component'; import { AuthService } from './auth.service'; class MockAuthService { checkAuthStatus() { return true; } } describe('MyComponent', () => { let component: MyComponent; let fixture: ComponentFixture<MyComponent>; beforeEach(() => { TestBed.configureTestingModule({ declarations: [MyComponent], providers: [ { provide: AuthService, useClass: MockAuthService } ] }); fixture = TestBed.createComponent(MyComponent); component = fixture.componentInstance; fixture.detectChanges(); }); it('should create', () => { expect(component).toBeTruthy(); }); it('should detect authenticated user', () => { const isAuth = component.authService.checkAuthStatus(); expect(isAuth).toBeTrue(); }); });
- 通过
providers
数组中的{ provide: AuthService, useClass: MockAuthService }
,在组件测试环境中用MockAuthService
替换了真实的AuthService
,方便测试组件与服务的交互。
- 通过