Javascript 什么';提供和注入的区别是什么';窗口';角度8和9中的vs窗口?

Javascript 什么';提供和注入的区别是什么';窗口';角度8和9中的vs窗口?,javascript,angular,typescript,dependency-injection,angular8,Javascript,Angular,Typescript,Dependency Injection,Angular8,我有两个使用这些版本的角度项目: 9.0.0-next.6 8.1.0 在版本9中,我使用它来提供并注入窗口对象: @NgModule({ providers: [ { provide: Window, useValue: window }, ] }) export class TestComponent implements OnInit { constructor(@Inject(Window) private window: Wi

我有两个使用这些版本的角度项目:

  • 9.0.0-next.6
  • 8.1.0

在版本9中,我使用它来提供并注入
窗口
对象:

@NgModule({
  providers: [
    {
      provide: Window,
      useValue: window
    },
  ]
})

export class TestComponent implements OnInit {
  constructor(@Inject(Window) private window: Window)
}
这很好用


采用这种方法处理版本8时,在编译过程中会抛出警告和错误:

警告:无法解析TestComponent的所有参数

我用单引号解决了这个问题,如下所示:

@NgModule({
  providers: [
    {
      provide: 'Window',
      useValue: window
    },
  ]
})

export class TestComponent implements OnInit {
  constructor(@Inject('Window') private window: Window)
}

两种版本之间的区别是什么?

角度8和角度9的差异是什么导致了这种情况?

考虑到
ValueProvider
界面:

export declare interface ValueProvider extends ValueSansProvider {
    /**
     * An injection token. Typically an instance of `Type` or `InjectionToken`, but can be `any`.
     */
    provide: any;
    /**
     * When true, injector returns an array of instances. This is useful to allow multiple
     * providers spread across many files to provide configuration information to a common token.
     */
    multi?: boolean;
}
provide
属性的类型为
any
。这意味着任何对象(包括
窗口
构造函数)都可以进入其中。对象实际上并不重要,只有引用重要,可以确定应该使用哪个提供程序在构造函数中注入参数

使用本机
窗口
构造函数作为注入令牌不应被视为一种良好做法。它在编译时失败,因为
窗口
在运行时存在于浏览器环境中,它也作为类型脚本
声明
存在,但Angular 8编译器无法进行静态代码分析,以关联提供程序中的
窗口
和构造函数参数中的
窗口
,因为
窗口的分配是由浏览器完成的,而不是由代码完成的。不知道为什么它在Angular 9中工作

您应该创建自己的表示依赖项提供程序的注入令牌。此注入令牌应为:

  • 专用字符串(就像您使用
    'Window'
  • 专用的
    注入令牌
    。例如
    export const window=new InjectionToken('window')

此外,角度代码应该是平台无关的(应该可以在浏览器和Node.js服务器上执行),因此最好使用返回
窗口
未定义
/
的工厂,然后在组件中处理
未定义的
/
情况。

为了让您的应用程序能够使用服务器端渲染,我建议您不仅使用window-through令牌,而且以SSR友好的方式创建此令牌,完全不引用
window
。Angular具有内置的
文档
令牌,用于访问
文档
。以下是我的项目通过令牌使用
window
的方法:

从'@angular/common'导入{DOCUMENT};
从'@angular/core'导入{injection,InjectionToken};
导出常量窗口=新注入令牌(
“全局窗口对象上的抽象”,
{
工厂:()=>{
const{defaultView}=inject(文档);
如果(!defaultView){
抛出新错误(“窗口不可用”);
}
返回默认视图;
},
},
);
编辑:由于这是人们经常需要的,我们使用此技术创建了一个小型开源库,其中包含全局对象的注入标记,因此您可以使用它:

在Angular Universal中,它有一个用于模拟的姊妹库,可与SSR一起使用:

总的来说,请查看我们的本地API中心:


我希望通过赏金,我能得到一个答案,我和其他人可以从中更好地了解提供者和di在Angular和框架的不同版本中的工作方式。非常感谢您的回答。这是非常有用的,我将来将使用类似的解决方案。@lampshade查看我们创建的这个小库,它有许多全局对象标记,如窗口、导航器、位置等:作为替代,您可以忽略显式错误
抛出
并按原样返回
defaultView
。因此,消费组件可以检查此.window
是否错误,因此可以轻松跳过与
window
相关的逻辑。我从未遇到过不可用的情况,包括SSR。这更像是一个让人满意的打字脚本。非常好!谢谢我只是检查了Angular文档(v8和v9),没有找到一个使用字符串的示例:(他们应该在文档中真正解释这一点!