【问题标题】:Why does Angular recommend to use a FactoryProvider for upgraded ajs services, instead of an InjectionToken?为什么 Angular 建议使用 FactoryProvider 来升级 ajs 服务,而不是 InjectionToken?
【发布时间】:2019-12-19 18:19:49
【问题描述】:

在他们的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) {
  }
}

【问题讨论】:

    标签: angular ng-upgrade angular-upgrade


    【解决方案1】:

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

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

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

    这种说法并不完全正确。

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

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

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

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

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

    【讨论】:

    • 我有点忘了这个问题,但无论如何,我问这个问题的部分原因是因为从 Angular 的角度来看,AngularJS 服务是单例的,它们可以用于任何角模块。因此,当我检查我参与的代码库中的一些旧代码时,我只是认为似乎没有必要跨多个模块提供 AngularJS 服务。主要原因是因为$injector.get('&lt;servicename&gt;') 应该每次都返回相同的实例。还是有一些我错过的情况不是这种情况?
    • 另外,我只是觉得InjectionToken 需要更少的样板代码,而不是当您决定开始使用 AngularJS 服务时必须更新每个模块。
    • 另外,如果升级后的服务需要注入到providedIn: 'root'的服务中,是不是也需要在根中,否则取决于根服务是什么模块第一次使用,可能没有升级后的服务可以注入。
    猜你喜欢
    • 2020-12-20
    • 2020-10-09
    • 1970-01-01
    • 2019-07-21
    • 1970-01-01
    • 1970-01-01
    • 2014-08-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多