51

我正在尝试通过新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为了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)。

我可以通过提供translationsResolveras a NgModule provider(在 providers 数组中)来解决这个问题,但我更喜欢它作为injectable提供者。

有什么解决这个问题的建议吗?

4

5 回答 5

27

我遇到了同样的问题。原来解决方案是“不要这样做”,正如其中一位 Angular 人在此线程中所解释的那样:https ://github.com/angular/angular-cli/issues/10170#issuecomment-380673276

正如我所收集的那样,当它们由根模块提供时,它归结为服务更容易摇树。

我和你一样失望。

于 2018-06-29T12:03:42.120 回答
22

更新 - 2019 年 10 月

我现在收到了 5 票赞成这个答案,所以我觉得我应该坦白说我实际上不再遵循我自己的建议(下)!

由于官方(并且广泛遵循)Angular 政策是使用 Angular 政策providedIn: 'root',我决定总的来说,如果我坚持这一点,其他开发人员不会感到困惑。到目前为止,它还没有给我带来任何问题,但是下面的警告仍然存在,我相信保持意识到这一点很重要。

原帖

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

providedIn语法似乎有两个主要好处

  1. 它支持对未使用的服务进行 tree-shaking
  2. providedIn: 'root'确保您只获得一个服务实例

但是只有在编写库而不是应用程序时才真正需要(1)(因为为什么要在应用程序中包含不需要的服务),并且可以避免多个服务实例(2)只需确保您不会多次导入服务模块。

语法的问题是:providedIn

  1. providedIn: 'root'打破了服务和它“居住”(或“与”)模块之间的联系——因为服务不知道模块,模块也不知道服务。这意味着该服务不再真正“属于”该模块,而只会与它的任何引用捆绑在一起。这反过来意味着现在由服务消费者来确保服务的可注入依赖项(如果有的话)在使用之前可用,这是令人困惑且非常违反直觉的(当然,除非依赖项以及它们的依赖项)依赖关系等 - 也是 all providedIn: 'root',在这种情况下它们会照顾自己)。
  2. 上述循环引用问题。如果服务实际上由同一模块中的任何组件使用,则实际上不可能通过这种语法保留服务与其模块之间的链接。

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

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

于 2019-05-25T10:38:33.280 回答
17

这不是 Angular 依赖问题。

循环引用是由 TypeScript 编译器在尝试解析循环导入时生成的。

第一个解决方案

创建一个名为的新模块,并在其中ProtectedResolversModule使用providedIn: ProtectedResolversModule和移动解析器。

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

第二种解决方案

使用providers数组ProtectedModule

于 2018-07-23T14:49:16.230 回答
1

在 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

“任何”对于确保服务是模块边界内的单例非常有帮助。它是“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);
    }
  }
于 2021-06-07T15:48:07.713 回答
0

从角度/核心检查forwardRef()函数。它允许引用尚未定义的引用。

import {MyService} from './service';

constructor(@Inject(forwardRef(() => MyService)) public myService: MyService) {
}
于 2018-06-28T07:28:33.020 回答