Angular 角度6+;:在非根模块中提供导致循环依赖
我正在尝试通过新的Angular 角度6+;:在非根模块中提供导致循环依赖,angular,typescript,angular6,angular7,Angular,Typescript,Angular6,Angular7,我正在尝试通过新的providedIn属性提供解析服务 这是我在受保护模块中使用的翻译解析器: 从'@angular/core'导入{Injectable}; 从“rxjs”导入{observatable,pipe}; 从“rxjs/operators”导入{map}; //这导致:“检测到循环依赖项中的警告:” 从“../../../protected/protected.module”导入{ProtectedModule}; 从“../../http/http handler.servic
providedIn
属性提供解析服务
这是我在受保护模块中使用的翻译解析器:
从'@angular/core'导入{Injectable};
从“rxjs”导入{observatable,pipe};
从“rxjs/operators”导入{map};
//这导致:“检测到循环依赖项中的警告:”
从“../../../protected/protected.module”导入{ProtectedModule};
从“../../http/http handler.service”导入{HttpHandlerService};
@注射的({
providedIn:ProtectedModule//在这里(我需要这一行的导入)
})
导出类TranslationsResolversService{
构造函数(私有httpHandlerService:httpHandlerService){}
resolve():任何{
//做点什么。。。
}
}
从角度/核心检查功能。它允许引用尚未定义的引用
从“/service”导入{MyService};
构造函数(@Inject(forwardRef(()=>MyService))公共MyService:MyService){
}
我遇到了同样的问题。事实证明,解决方案是“不要这样做”,正如其中一个有棱角的家伙在这篇文章中所解释的:
据我所知,归根结底,当服务由根模块提供时,它们更容易树抖动
我和你一样失望。这不是角度相关性问题 当TypeScript编译器尝试解析循环导入时,循环引用由它生成 第一种解决方案 创建一个名为
ProtectedResolversModule
的新模块,并使用在:ProtectedResolversModule中提供的将解析程序移动到该模块
现在,您可以将该模块导入到ProtectedModule
中,并且在加载ProtectedRoutingModule
时不会出现循环依赖项错误
第二种解决方案
使用ProtectedModule
的providers
数组 更新日期:2019年10月
我已经收到了5张赞成票,所以我觉得我应该坦率地说,我不再真正遵循我自己的建议(见下文)
由于官方的(并且被广泛采用的)Angular策略是使用“root”中提供的,因此我决定,总体而言,如果我坚持这样做,其他开发人员就不会那么困惑了。到目前为止,它还没有给我带来任何问题,但下面的警告仍然存在,我相信保持对这一点的意识是很重要的
原职
我认为Angular把
语法中提供的弄得有点乱。这似乎让很多人感到困惑。例如,请参见以下两个github线程:
在
语法中提供的似乎有两个主要好处:
它支持未使用服务的树抖动
providedIn:'root'
确保您只能获得一个服务实例
但是,如果您正在编写库而不是应用程序,那么您只需要(1)(因为为什么要在应用程序中包含不需要的服务),并且您可以通过确保不多次导入服务模块来避免多个服务实例(2)
语法中提供的的问题有:
providedIn:'root'
中断服务与它“所在”(或“使用”)的模块之间的链接-因为服务不知道模块,模块也不知道服务。这意味着该服务不再真正“属于”该模块,只会与引用它的任何内容捆绑在一起。这反过来意味着,现在由服务使用者来确保服务的可注入依赖项(如果有)在使用之前可用,这会让人感到困惑,而且非常不直观(当然,除非依赖项以及它们的依赖项等也都在“root”中提供,在这种情况下,它们会自行处理)
上面描述的循环引用问题。如果同一模块中的任何组件实际使用服务,则实际上不可能通过此语法保留服务与其模块之间的链接
这与官方角度指南相反,但我的建议是:不要使用中提供的
,除非您正在编写需要摇树的第三方库——在模块上使用旧的(未弃用的)提供程序
语法,即:
@NgModule({providers:[MyService],})
在Angular9中+
您可以使用providerIn:任何
基本上它的工作原理与模块类似,但您不直接使用模块,因此不再存在循环依赖关系
文件:
“any”:在每个延迟加载的模块中提供一个唯一的实例,而所有急切加载的模块共享一个实例
换句话说,它位于不同的注入树中。它与您在其他模块中使用的实例不同
更多裁判
“Any”非常有助于确保服务是模块边界内的单例服务。它是“root”的一个可靠替代方案,以确保各个模块之间不会产生副作用
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);
}
}
private-injectableDefInScope(def:ɵɵInjectableDef):布尔值{
如果(!def.providedIn){
返回false;
}else if(typeof def.providedIn=='string'){
返回def.providedIn=='any'| |(def.providedIn===this.scope);
}否则{
返回此.injectorDefTypes.has(def.providedIn);
}
}
Ozgur我不确定这对解决循环依赖性有何帮助。与其在路由中注入服务,不如使用构造函数。在解析阶段,我必须在路由中“注入”(注册更正确)解析程序。我还想使用providedIn语法来标记解析程序的范围