Angular 中的服务层
Source: Dev.to
根级服务:全局 MVP 🌍
当你使用 Angular CLI(ng generate service)生成服务时,默认代码如下:
@Injectable({
providedIn: 'root'
})
export class UserService { }
Angular 会创建 唯一的实例 并在整个应用中共享它。
可以把它想象成酒店前台的接待员:所有组件都与同一个接待员对话,得到相同的信息。
常见使用场景
- 认证服务 – 在所有组件之间共享登录状态
- 配置服务 – 全局应用设置,且不会变化
- HTTP/API 服务 – 与后端通信的单一入口
- 状态管理 – 多个组件需要共享的数据
根级服务是大多数场景的首选,因为它们简单、高效,且避免了不必要的实例化。
组件级服务:本地化 🏠
如果一个服务只应由单个组件使用——或者每个组件实例都需要自己的副本——可以在组件层面提供它:
@Component({
selector: 'app-shopping-cart',
templateUrl: './shopping-cart.component.html',
providers: [CartService]
})
export class ShoppingCartComponent { }
每当创建该组件时,Angular 会为该组件 新建一个实例 的 CartService。
类比:每个酒店房间都有专属的管家;101 房间有自己的管家,102 房间有另一位管家,它们之间不共享信息。
何时使用
- 表单状态 – 每个表单组件保存自己的数据
- 组件特定逻辑 – 必须防止泄漏到其他组件的数据
- 多个实例 – 同一组件在页面上出现多次且需要独立行为
示例:在多个页面上展示的 ProductFilterComponent,每个实例都记住自己的过滤条件。
模块级服务:折中方案 ⚖️
如果你使用 Angular 模块(而不是独立组件),可以在模块层面提供服务:
@NgModule({
declarations: [...],
imports: [...],
providers: [AuthGuardService]
})
export class AdminModule { }
急加载模块
当模块在应用启动时加载,服务的行为类似于整个应用的单例——等同于 providedIn: 'root'。
懒加载模块
当模块以懒加载方式加载(例如通过路由),Angular 会为该模块创建 独立的注入器,从而为服务提供 新的实例,其作用域仅限于该懒加载特性。
const routes: Routes = [
{ path: 'admin', loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule) }
];
在这种情况下,AdminService 只存在于懒加载的 admin 模块内部,模块卸载时也随之销毁。
应该使用哪种方式? 🤔
| 问题 | 推荐作用域 |
|---|---|
| 服务是否需要在整个应用中使用? | 根级 ✅ |
| 服务是否只被单个组件使用? | 组件级 ✅ |
| 服务是否限定在需要懒加载的特性模块中? | 模块级 ✅ |
理解 Angular 依赖注入 层级——注入器如何沿组件树向上解析依赖——有助于你决定合适的作用域。
结论 💡
- 根级:唯一实例,整个应用共享。
- 组件级:每个组件拥有新实例。
- 模块级:实例取决于急加载还是懒加载。
选择正确的层级可以让你的应用易于维护且性能良好;错误的选择则会让调试变得头疼。