5

当 Angular 4.0.2 应用程序被提前编译时,提供者被定义为useValue

import { OpaqueToken, Provider } from '@angular/core';

export const windowToken = new OpaqueToken('window');
export const windowProvider = { provide: windowToken, useValue: window };

并像使用

@NgModule({ providers: [windowProvider], ... })
export class AppModule {}

它编译正常,但在window注入undefined时导致

constructor(@Inject(windowToken) window) {
   window.navigator...
}

引导时引发错误:

TypeError:无法读取未定义的属性“导航器”

仔细查看自动生成的 app.module.ngfactory.js 似乎确实是undefined

...
import * as import39 from './window';
var AppModuleInjector = (function (_super) {
    ...
    AppModuleInjector.prototype.createInternal = function () {
        ...
        this._windowToken_26 = undefined;
        this._SomeService_27 = new import16.SomeService(this._windowToken_26);
    }
    AppModuleInjector.prototype.getInternal = function (token, notFoundResult) {
        ...
        if ((token === import39.windowToken)) {
            return this._windowToken_26;
        }
        ...

当使用相同的服务时useFactory,一切正常:

export function windowFactory() {
  return window;
}
export const windowProvider = { provide: windowToken, useFactory: windowFactory };

window在这里使用作为提供者到底有什么问题useValue?这是一个已知的陷阱吗?此限制是否适用于所有全局变量或所有useValue提供程序?

4

2 回答 2

3

我遇到了类似的问题,但它与 SignalrWindow 有关。概念和错误虽然是相同的。

然后我在这里找到了这篇文章(https://blog.sstorie.com/integrating-angular-2-and-signalr-part-2-of-2/),文章底部的一些评论很有帮助我解决问题。

基本上,在提供程序中使用工厂方法而不是 useValue 就可以完成。我不确定为什么会出现问题,但我知道这种方法可以解决 aot 问题。

修复步骤:

创建一个导出的函数

export function windowFactory(): any {
    return window;
}

然后在核心模块中,在@NgModule提供者中你可以这样做:

...
providers: [
    { provide: SignalrWindow, useFactory: windowFactory }
  ]
...

基本上,您可以根据自己的喜好重命名方法(因此,在您的示例中它将是:)

export const windowProvider = { provide: windowToken, useFactory: windowFactory };
于 2017-07-03T12:48:54.967 回答
1

在 AoT 编译期间,Angular CLI 静态分析代码也生成 ngmodule.factory 文件。它看到“useValue”并检查静态值是否可用并将其放入 ngmodule.factory。在编译期间,此值不可用,因此它保留该提供程序值,因此,当注入构造函数时,它作为“未定义”返回。

但是,提供“useFactory”的目的与您直到运行时才知道您的价值相同的目的。

因此,useValue 在您的场景中不起作用,但“useFactory”将起作用。

底线:在 AOT 编译时,仅当您具有常量字符串或数字等静态值时才使用“useValue”。否则使用“useFactory”返回运行时计算的对象/值。

于 2017-12-08T21:30:27.550 回答