Angular2:2服务相互依赖

时间:2016-04-02 21:12:39

标签: angular

在我的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

装饰

在其中一个服务中评论构造函数时,应用程序运行正常。 所以我的猜测是两个服务的“交叉引用”导致了这个问题。 你知道这里出了什么问题吗? 或者我的方法已经错了?

感谢您的建议!

13 个答案:

答案 0 :(得分:33)

这是一种称为循环依赖的。这不是Angular2本身的问题。我所知道的任何语言都不允许这样做。

您需要重构代码以删除此循环依赖项。您可能需要将其中一项服务分解为新服务。

如果您遵循单一责任原则,您将发现您不会进入循环依赖陷阱。

答案 1 :(得分:27)

构造函数注入可防止循环依赖。

可以通过注入Injector并强制请求依赖关系来解决它:

private payrollService:PayrollService;
constructor(/*private payrollService:PayrollService*/ injector:Injector) {
  setTimeout(() => this.payrollService = injector.get(PayrollService));
}

另见Circular dependency injection angular 2

答案 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文档中有一章关于循环依赖。我觉得非常有用。

Dependency injection

答案 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)

使用接口 - 这是许多语言中的常见模式。

见Günters答案

Circular dependency with Angular 2 and SystemJS

答案 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并不是在自言自语,我的例子将是关于我的案子

请注意,导入不会影响循环依赖问题。

rabbit.component.ts

export class RabbitComponent {

    public rabbitsArray: Rabbit[] = []

    constructor(){
        let lRabbit: Rabbit = new Rabbit(God.rabbitMotherFromEve())
        lRabbit.setRabbitComponent(this)
        rabbits.push(lRabbit)
    }
}

rabbit.ts

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可以有多个BB可以有一个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;