首页 > 解决方案 > 为什么 Angular 建议使用 FactoryProvider 来升级 ajs 服务,而不是 InjectionToken?

问题描述

在他们的文档中,他们使用这个FactoryProvider例子来升级 ajs 服务:

import { HeroesService } from './heroes.service';

export function heroesServiceFactory(i: any) {
  return i.get('heroes');
}

export const heroesServiceProvider = {
  provide: HeroesService,
  useFactory: heroesServiceFactory,
  deps: ['$injector']
};

@NgModule({
  imports: [
    BrowserModule,
    UpgradeModule
  ],
  providers: [
    heroesServiceProvider
  ],
/* . . . */
})

有什么理由不这样做InjectionTokenproviders

import { HeroesService } from './heroes.service';
import {inject, InjectionToken} from '@angular/core';
import {auto} from 'angular';

export const heroesServiceToken = new InjectionToken<HeroesService>('HeroesServices', {
  providedIn: 'root',
  factory() {
    const $injector = inject('$injector' as any) as auto.IInjectorService;
    const instance = $injector.get('heroes');
    return instance as HeroesService;
  }
});

...
import { HeroesService } from './heroes.service';
import {Inject} from '@angular/core';

class SomeComponent {
  constructor(@Inject(heroesServiceToken) private heroesService: HeroesService) {
  }
}

标签: angularng-upgradeangular-upgrade

解决方案


InjectionToken通常没有与它们关联的值。当您需要使非令牌值可注入(即 an Interface)时,它们很方便。我认为工厂的选项是在更高版本的 Angular 中添加的,一旦有了工厂,令牌就会有一个关联的值。因此,不应在提供程序数组中使用带有工厂的令牌。

我觉得文档使用了最常见的用例,并且更容易让人理解。

这样您就不必将它添加到需要使用的每个模块的提供程序列表中?

这种说法并不完全正确。

如果模块需要提供它,您可以将它添加到模块中的提供程序中。当一个模块需要使用它时,会注入提供者,并通过找到提供它的父注入器来解析该值。将提供程序添加到根目录往往会使每个人都可以使用它。

让提供者进入目录可能很棘手。因此,Angular 编译器会查找注入以查看它是否正在被使用,如果它找到一个用法,编译的应用程序会将其添加到provideIn声明中。否则,我们必须手动提供。

我说很棘手,因为let thing = injector.get(myThing)编译器不会拾取源代码。构造函数参数和@Inject()是我知道编译器会看到的唯一东西。

使用带有令牌的工厂隐藏了该值的生命周期。除非有人去查看令牌的声明位置,否则他们将不知道它是如何创建的。在模块中提供工厂更常见,人们会看到它。

如果您需要provideIn工厂一起使用,那么我认为令牌是唯一的方法。


推荐阅读