在我的Angular 2应用程序中,我有两个相互依赖的服务(来自服务B的服务A调用方法,反之亦然)。 以下是相关代码: 在app.component.ts中:
import {Component} from 'angular2/core';
import {TempService} from '../services/tmp';
import {Temp2Service} from '../services/tmp2';
@Component({
selector: 'my-app',
templateUrl: 'app/app/app.component.html',
providers: [TempService, Temp2Service]
})
export class AppComponent { (...) }
服务1:
import {Injectable} from 'angular2/core';
import {Temp2Service} from './tmp2';
@Injectable()
export class TempService {
constructor (private _sessionService: Temp2Service) {}
}
服务2:
import {Injectable} from 'angular2/core';
import {TempService} from './tmp';
@Injectable()
export class Temp2Service {
constructor (private _sessionService: TempService) {}
}
运行应用程序会导致以下错误:
EXCEPTION:无法解析所有参数 'Temp2Service'(未定义)。确保所有参数都是 用Inject修饰或具有有效的类型注释 'Temp2Service'用Injectable
装饰
在其中一个服务中评论构造函数时,应用程序运行正常。 所以我的猜测是两个服务的“交叉引用”导致了这个问题。 你知道这里出了什么问题吗? 或者我的方法已经错了?
感谢您的建议!
答案 0 :(得分:33)
这是一种称为循环依赖的。这不是Angular2本身的问题。我所知道的任何语言都不允许这样做。
您需要重构代码以删除此循环依赖项。您可能需要将其中一项服务分解为新服务。
如果您遵循单一责任原则,您将发现您不会进入循环依赖陷阱。
答案 1 :(得分:27)
构造函数注入可防止循环依赖。
可以通过注入Injector
并强制请求依赖关系来解决它:
private payrollService:PayrollService;
constructor(/*private payrollService:PayrollService*/ injector:Injector) {
setTimeout(() => this.payrollService = injector.get(PayrollService));
}
答案 2 :(得分:13)
这里的关键不是通过构造函数注入服务,而是使用显式setter&干将。我会在Angular 4中使用以下模式:
<强> app.component.ts 强>
import { FooService } from './foo/foo.service';
import { BarService } from './bar/bar.service';
export class AppComponent {
constructor(public fooService: FooService, public barService: BarService) {
this.fooService.setBarService(barService);
}
}
<强> foo.service.ts 强>
@Injectable()
export class FooService {
barService: any;
constructor(){
}
setBarService(barService: any): void {
this.barService = barService;
}
getBarService(): any {
return this.barService;
}
}
答案 3 :(得分:7)
Angular 2文档中有一章关于循环依赖。我觉得非常有用。
答案 4 :(得分:6)
我更新了此解决方案以使用Angular&gt; 4.使用Injector类,您可以将服务注入另一个服务
import { Injector } from '@angular/core';
import { TempService } from './tmp';
@Injectable()
export class Temp2Service {
private tempService: any;
constructor (private injector: Injector) { }
public funcA() {
this.tempService = this.injector.get(TempService);
this.tempService.doSomething();
}
}
答案 5 :(得分:3)
这是一个循环依赖,不幸的是,这是一个基本的计算机科学问题,或信息问题,Angular无法解决的问题。尝试做这样的事情:
export class ServiceA{
constructor(private b: ServiceB){
b.setA(this);
}
}
export class ServiceB {
private a: ServiceA
constructor(){
}
setA(a){
this.a = a;
}
}
这可能是最好的方法。
答案 6 :(得分:1)
如果没有可接受的单件,您可以尝试在其中一个服务上调用NEW。像
html.to_s
这是我采用的方法,因为这两种服务都没有使用未定义的成员变量。
答案 7 :(得分:1)
如果您正在使用Angular 2,并且在某些事件上需要循环依赖关系来调用彼此的函数,您可以使用Observables并在Service中订阅它们,其中您注入了其他服务。
小例子: -
@Injectable()
class Service1{
observeEvents(){
return Obsevable.create((o)=>{
//store `o` it in any class variable
//whenever you want to call function of Service2 from this class, do this `o.next('method_name');`
});
}
}
@Injectable()
class Service2{
constructor(private service1: Service1){
this.service1.subscribe((method)=>{
this[method]();
});
}
}
答案 8 :(得分:1)
我们可以解决forwordRef函数来解决这个问题。
//允许引用尚未定义的引用。
@Inject(forwardRef(()=&gt; MyService))private httpProxy:MyService
答案 9 :(得分:0)
答案 10 :(得分:0)
我尝试用setTimeout修复循环依赖警告或使用注入器的所有操作,并将注入从构造函数移到另一个函数中对我来说都不起作用,对于角度7。
这是我的工作解决方案:
我创建了另一个服务,只是为了保留对第一个服务的引用:
@Injectable()
export class AnotherService {
private _service: AService;
get service(): AService {
return this._service;
}
set service(service: AService) {
this._service = service;
}
}
然后我可以像这样使用它:
@Injectable()
export class AService {
constructor(private anotherService: AnotherService) {
anotherService.service = this;
}
...
}
在这里:
@Injectable()
export class BService {
private aService: AService;
constructor(private injector: Injector) {
const anotherService = injector.get(AnotherService);
this.aService = anotherService.service;
}
...
}
答案 11 :(得分:0)
我遇到了循环依赖问题,找到了很多答案,而我找到的最佳解决方法是。
据我了解,当您尝试将a: A
传递给b: B
到构造函数中时,就会出现问题。因此,避免这种情况的方法是创建您的对象,然后仅将a
设置为b
至于我A和B并不是在自言自语,我的例子将是关于我的案子
请注意,导入不会影响循环依赖问题。
export class RabbitComponent {
public rabbitsArray: Rabbit[] = []
constructor(){
let lRabbit: Rabbit = new Rabbit(God.rabbitMotherFromEve())
lRabbit.setRabbitComponent(this)
rabbits.push(lRabbit)
}
}
export class Rabbit {
public feetsArray: Foot[] // I know its not the best practices but more concise for example
public rabbitComponent: RabbitComponent
constructor (anyThingYouWantButRabbitComponent: RabbitMother){
}
}
答案 12 :(得分:0)
查询API时遇到问题。 A
可以有多个B
,B
可以有一个A
父级。在建立这些模型时,需要避免其中一种关系,以避免循环依赖。然后,当您查询时,只需将类型强制转换为any
:
this.repositoryService.Query<A>(`$filter=Id eq ${B.AId}`).subscribe(As=>this.importantProp = (As[0] as any).C.property;)
然后在您对A的定义中:
@JsonProperty('B', [Object], true) Bs = new Array<Object>();
@JsonProperty('C', [Object], true) C = null;