Angular 6+:Provided在非根模块中导致循环依赖

时间:2018-06-27 11:58:12

标签: angular typescript angular6 angular7

我正在尝试通过新的providedIn属性提供解析服务。

这是我在受保护的模块中使用的翻译解析器:

import { Injectable } from '@angular/core';

import { Observable , pipe } from 'rxjs';
import {map} from "rxjs/operators";

//This is causing: "WARNING in Circular dependency detected:"
import {ProtectedModule} from "../../../protected/protected.module";

import { HttpHandlerService } from '../../http/http-handler.service';

@Injectable({
  providedIn: ProtectedModule //Over here (I need the import for this line)
})
export class TranslationsResolverService {
  constructor(private _httpHandlerService : HttpHandlerService) { }
    resolve(): any {
      //Do Something...
    }
}

我在受保护的路由模块中声明了翻译解析器服务:

import { NgModule }           from '@angular/core';
import {RouterModule, Routes} from '@angular/router';

import {AuthGuard} from "../core/resolvers/auth/auth.guard";
import {TranslationsResolverService} from "./../core/resolvers/translations/translations-resolver.service";

const routes: Routes = [
  {
    path : 'app' ,
    component: ProtectedComponent,
    resolve : {
      translations : TranslationsResolverService // <---- Over here - i can't remove that of course
    },
    canActivate: [AuthGuard],
    ]
  }
];


@NgModule({
  imports : [RouterModule.forChild(routes)],
  exports : [RouterModule]
})
export class ProtectedRoutingModule { }

由于我在protected.module中导入({typescript import)translations-resolver.service.ts 以便在providedIn属性中使用它的事实,警告:已检测到循环依赖项:

path/to/translations-resolver.service.ts -> 

protected/protected.module.ts ->

protected/protected-routing.module.ts -> 

path to translations-resolver.service.ts

由于providedIn属性,添加了第二条路径(protected / protected.module.ts)。

我可以通过仅将translationsResolver作为NgModule provider(在providers数组中)来解决此问题,但我更喜欢将其作为injectable的provider。

有解决此问题的建议吗?

5 个答案:

答案 0 :(得分:9)

我遇到了同样的问题。事实证明,解决方案是“不要这样做”,正如一位Angular员工在此主题中所解释的:https://github.com/angular/angular-cli/issues/10170#issuecomment-380673276

归结为当我收集时,由根模块提供的服务更容易摇晃。

我和你一样失望。

答案 1 :(得分:7)

这不是Angular依赖问题。

TypeScript编译器尝试解析循环导入时,会生成循环引用。

第一个解决方案

创建一个名为ProtectedResolversModule的新模块,并使用providedIn: ProtectedResolversModule并将解析器移到那里。

现在,您可以将该模块导入ProtectedModule,并且在加载ProtectedRoutingModule时不会出现循环依赖项错误。

第二个解决方案

使用providers的{​​{1}}数组。

答案 2 :(得分:1)

我认为Angular的providedIn语法有点混乱。似乎使很多人感到困惑。例如。看到这两个github线程:

providedIn语法似乎有两个主要的优点

  1. 它支持对未使用的服务进行摇动
  2. providedIn: 'root'确保仅获得服务的一个实例

但是如果只编写而不是应用,则只需要(1)(因为为什么要包含不需要的服务在应用程序中),并且只需确保不多次导入服务模块就可以避免使用多个服务实例(2)。

使用providedIn语法的问题是:

  1. providedIn: 'root'中断了服务与其“所在”(或“带有”)模块之间的链接-因为该服务不了解该模块,而该模块也不了解该服务。这意味着该服务不再真正属于该模块,而将与该模块的任何引用捆绑在一起。反过来,这意味着现在要由服务消费者来确保在使用服务之前,该服务的可注入依赖项(如果有)是可用的,这很容易混淆,而且违反直觉。 / li>
  2. 上述循环参考问题。通过这种语法,实际上不可能-要保留服务及其模块之间的链接,如果该服务实际上被同一模块内的任何组件使用

这与Angular官方指南相反,但我的建议是:请勿使用providedIn,除非您正在编写需要摇摇晃晃的第三方库-使用而不是模块上的旧(未弃用)providers语法,即:

@NgModule({ providers: [MyService], })

答案 3 :(得分:0)

从角度/芯线检查forwardRef()功能。它允许引用尚未定义的引用。

import {MyService} from './service';

constructor(@Inject(forwardRef(() => MyService)) public myService: MyService) {
}

答案 4 :(得分:0)

在 Angular9+ 中

你可以使用 providerIn: Any

基本上它就像模块一样工作,但是你不直接使用模块所以没有更多的循环依赖

文档:https://angular.io/api/core/Injectable#options

<块引用>

'any' :在每个延迟加载的模块中提供一个唯一的实例,而所有急切加载的模块共享一个实例。

换句话说,它在不同的注入树中。它与您在其他模块中使用的实例不同。

更多参考

https://dev.to/christiankohler/improved-dependeny-injection-with-the-new-providedin-scopes-any-and-platform-30bb

<块引用>

'Any' 非常有助于确保服务是模块边界内的单例。它是“root”的强大替代方案,可确保各个模块不会相互产生副作用。

https://indepth.dev/posts/1151/a-deep-dive-into-injectable-and-providedin-in-ivy

providerIn 的代码

  private injectableDefInScope(def: ɵɵInjectableDef<any>): boolean {
    if (!def.providedIn) {
      return false;
    } else if (typeof def.providedIn === 'string') {
      return def.providedIn === 'any' || (def.providedIn === this.scope);
    } else {
      return this.injectorDefTypes.has(def.providedIn);
    }
  }