Angular2:2服务相互依赖

Dan*_*iel 57 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 { (...) }
Run Code Online (Sandbox Code Playgroud)

服务1:

import {Injectable} from 'angular2/core';
import {Temp2Service} from './tmp2';

@Injectable()
export class TempService {
  constructor (private _sessionService: Temp2Service) {}
}
Run Code Online (Sandbox Code Playgroud)

服务2:

import {Injectable} from 'angular2/core';
import {TempService} from './tmp';

@Injectable()
export class Temp2Service {
  constructor (private _sessionService: TempService) {}
}
Run Code Online (Sandbox Code Playgroud)

运行该应用程序会导致以下错误:

EXCEPTION:无法解析'Temp2Service'的所有参数(未定义).确保所有参数都使用Inject进行修饰或具有有效的类型注释,并且'Temp2Service'使用Injectable进行修饰

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

谢谢你的建议!

Mar*_*tin 34

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

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

在你遵循单一的负责任原则,你会发现你不会进入循环依赖陷阱.

  • 实际上,我所知道的所有语言都允许循环依赖.问题是构造函数需要依赖项.如果不是,你可以做'a a = new A(); 设b = new B(); ab = b; ba = a;`.你仍然会有循环依赖,但一切都会正常运行.我不是说循环依赖是一件好事.只是说他们是可能的. (70认同)
  • `forwardRef`用于同一文件中类的循环依赖.我的答案是DI依赖关系.`forwardRef`不会对注入的循环构造函数依赖性产生任何影响.从构造上除去一个依赖打破循环,而是注入`Injector`和使用`的setTimeout(()=> {this.someDep = injector.get(SomeDependency);}`将解决的一种方法. (4认同)
  • "在你遵循单一的负责任原则,你会发现你不会陷入循环依赖陷阱." 这似乎是一个错误的陈述.我有一个视图,可以显示为页面的一部分,或显示为模式对话框.我的视图显示了相关模型,您可以单击该模型以在模态对话框中查看.在Angular的眼中,这会创建一个循环依赖(模态不会注入构造函数).实际视图的责任在两种情况下都没有区别(显示模型),但它创建了循环依赖.不过,我很欣赏我的情景与问题不同. (4认同)
  • 您无需重构代码.只是不要使用基于构造函数的注入.使用显式注射.为什么这是最佳答案? (4认同)
  • 在某些情况下,无法避免循环依赖。我发现 Julian FARHI 引用前向参考的答案很有用。解决了我的问题。 (2认同)

Gün*_*uer 28

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

它可以通过注入Injector和请求依赖性来分解,例如:

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

另请参见循环依赖注入角度2

  • 你能指望什么?构造函数注入不能与循环依赖项一起使用.唯一不错的选择是摆脱圈子. (6认同)

Cha*_*son 17

这里的关键不是通过构造函数注入服务,而是使用显式setter和getter.我会在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);

  }

}
Run Code Online (Sandbox Code Playgroud)

foo.service.ts

@Injectable()
export class FooService {

    barService: any;

    constructor(){
    }

    setBarService(barService: any): void {
        this.barService = barService;
    }

    getBarService(): any {
        return this.barService;
    }

}
Run Code Online (Sandbox Code Playgroud)

  • 基于KISS原则,应该考虑正确的答案 (2认同)
  • @Dimas Crocco感谢您的评论.我同意.提供理论很好,但最终,OP想要一个具体的例子,我觉得我给了他. (2认同)

小智 7

Angular 2文档中有一章关于循环依赖.我觉得非常有用.

依赖注入

  • 链接更改后,这样的答案就没有答案。另外,您还会让人们从链接的内容中猜测您的意思。只需引用您的意思并加以解释,以使您的答案成为实际答案(即使链接无效)。 (7认同)

Ant*_*nge 5

我更新了此解决方案以使用Angular> 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();
  }
}
Run Code Online (Sandbox Code Playgroud)


Ale*_*lls 5

这是一个循环依赖,不幸的是,这是一个基本的计算机科学问题或信息问题,这是 Angular 无法解决的问题。尝试做这样的事情:

export class ServiceA{
 constructor(private b: ServiceB){
    b.setA(this);
 }
}

export class ServiceB {

 private a: ServiceA

 constructor(){

 }

 setA(a){
   this.a = a;
 }

}
Run Code Online (Sandbox Code Playgroud)

这可能是最好的方法。