为什么Angular建议对升级的ajs服务使用FactoryProvider而不是InjectionToken?

时间:2019-12-19 18:19:49

标签: angular ng-upgrade angular-upgrade

在他们的documentation中,他们使用以下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
  ],
/* . . . */
})

是否有任何理由不使用InjectionToken来做到这一点,因此不必为每个需要使用的模块将其添加到providers列表中在吗?

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) {
  }
}

1 个答案:

答案 0 :(得分:0)

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

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

  

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

那句话并不完全正确。

如果需要该模块提供,则将其添加到模块中的提供商中。当模块需要使用时,将注入提供程序,并通过找到提供它的父注入器来解析该值。将提供程序添加到 root 倾向于使所有人均可使用。

将提供程序插入 可能很棘手。因此,Angular编译器会寻找注入以查看是否正在使用它,并且如果发现使用情况,编译后的应用程序会将其添加到provideIn声明中。否则,我们必须手动提供它。

我说起来很棘手,因为编译器未获取诸如let thing = injector.get(myThing)之类的源代码。我唯一知道编译器将看到的构造函数参数和@Inject()

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

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