0%

angular-di-injection-context

Injection Context - 顾名思义,注入上下文,说的通俗点,就是在Angular代码中,什么位置可以注入,比如我们最常用的constructor就属于一个Injection Context,因为你可以在constructor中注入服务。

Angular支持的Injection Context有如下几种:

  1. In class constructor
  2. In the initializer for fields of such classes.
  3. In the factory function specified for useFactory of a Provider or an @Injectable
  4. In the factory function specified for an InjectionToken.
  5. Within a stack frame that runs in an injection context. - 这是个啥?我咋看不懂捏?

In class constructor

constructor是我们最常用的注入位置,比如我们在组件中注入服务,就是在constructor中注入的。

新的写法, 使用inject函数

1
2
3
4
5
export class AppComponent {
constructor() {
private service: MyService = inject(MyService);
}
}

旧的写法

1
2
3
4
5
export class AppComponent {
constructor(private service: MyService) {
console.log(service);
}
}

In the initializer for fields of such classes

这个是啥意思呢?就是在类的字段初始化器中,也可以注入服务,比如下面的DataService.

1
2
3
4
5
6
export class AppComponent {
private service: MyService = inject(MyService);
constructor() {
console.log(this.service);
}
}

Stack frame in an injection context

有些函数被设计成可以运行在injection context中,比如我们常用的路由守卫(router guard), 之所以这样是为了能让我们在路由守卫中注入服务。比如下面的canActivateTeam函数,就是一个路由守卫。在这个函数里,我们可以注入PermissionsServiceUserToken。这样就可以判断用户是否有权限访问某个页面。

1
2
3
4
const canActivateTeam: CanActivateFn =
(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => {
return inject(PermissionsService).canActivate(inject(UserToken), route.params.id);
};

Run within an injection context

有时候我们需要讲一个函数运行在injection context中,但是当前上下文并不是injection context, 这时,我们可以使用runInInjectionContext函数来创建一个新的injection context, 然后在这个新的injection context中运行我们的函数。

比如Angular框架要求effect函数是必须运行在injection context中,所以我们通常在构造函数体中运行effect函数,如果我们想在ngOnInit函数中运行effect函数呢?因为ngOnInit函数并不是injection context, 这时我们就可以使用runInInjectionContext函数来运行effect函数。

注意:使用runInInjectionContext函数需要一个EnvironmentInjector

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
export class CountComponent implements OnInit {
count = signal(0);
doubleCount = computed(() => this.count() * 2);

private environmentInjector = inject(EnvironmentInjector);

constructor() {
// effect(() => {
// console.log('count:', this.count());
// console.log('doubleCount:', this.doubleCount());
// });
}

ngOnInit() {
runInInjectionContext(this.environmentInjector, () => {
effect(() => {
console.log('count:', this.count());
console.log('doubleCount:', this.doubleCount());
});
})
}
}

References

  1. https://angular.dev/guide/di/dependency-injection-context