是否可以同时在另一个服务中注入服务,反之亦然?

时间:2022-05-04 23:01:26

I have a real scenario in a real project where I need 2 services to access the properties and/or methods of each other. I'm not an Angular expert so is it possible?

我在一个真实的项目中有一个真实的场景,我需要2个服务来访问彼此的属性和/或方法。我不是Angular专家所以它可能吗?

I have tried and it fails. Here's my attempt:

我试过但它失败了。这是我的尝试:

app.component.ts

import { Component } from '@angular/core';
import { FirstService } from './first.service';
import { SecondService } from './second.service';

@Component({
  selector: 'my-app',
  template: '<h1>Hello world!</h1>',
  providers: [FirstService, SecondService]
})
export class AppComponent {

  constructor(public firstService: FirstService, public secondService: SecondService) {
    console.log(firstService.foo);
    console.log(secondService.bar);
  }

}

first.service.ts

import { Injectable } from '@angular/core';
import { SecondService } from './second.service';

@Injectable()
export class FirstService {

  foo: string = 'abc';

  constructor(public secondService: SecondService) {
    this.foo = this.foo + this.secondService.bar;
  }

}

second.service.ts

import { Injectable } from '@angular/core';
import { FirstService } from './first.service';

@Injectable()
export class SecondService {

  bar: string = 'xyz';

  constructor(public firstService: FirstService) {
    this.bar = this.bar + this.firstService.foo;
  }

}

Plunker: http://plnkr.co/edit/PQ7Uw1WHpvzPRf6yyLFd?p=preview

Just injecting the second service into the first service works fine but as soon as I inject the first service into the second service it fails and throws errors to the console.

只是将第二个服务注入到第一个服务中工作正常,但是一旦我将第一个服务注入第二个服务,它就会失败并向控制台抛出错误。

So what is wrong?

那有什么不对?

A working solution should print the following to the console log:

工作解决方案应将以下内容打印到控制台日志:

abcxyz
xyzabc

Thanks in advance!

提前致谢!

3 个解决方案

#1


3  

AngularJS does not allow injection of circular dependencies.

AngularJS不允许注入循环依赖项。

Miško Hevery, one of the authors of AngularJS, recommends finding the common elements:

AngularJS的作者之一MiškoHevery建议找到共同的元素:

+---------+      +---------+
|    A    |<-----|  B      |
|         |      |  |  +-+ |
|         |      |  +->|C| |
|         |------+---->| | |
|         |      |     +-+ |
+---------+      +---------+

And extracting it to a third service:

并将其提取到第三个服务:

                         +---------+
+---------+              |    B    |
|    A    |<-------------|         |
|         |              |         |
|         |    +---+     |         |
|         |--->| C |<----|         |
|         |    +---+     +---------+
+---------+

For more information, see Circular Dependency in constructors and Dependency Injection by Miško Hevery.

有关更多信息,请参阅MiškoHevery中的构造函数中的循环依赖关系和依赖关系注入。

#2


3  

I'm not an Angular expert so is it possible

我不是角色专家,所以有可能

No. Circular dependencies are not resolved by angular's DI.

不可以。通过角度的DI不能解决循环依赖关系。

Also even systems that do support it, quite commonly are inconsistent e.g. commonjs https://nodejs.org/docs/latest/api/modules.html#modules_cycles will give you an empty object for a while.

即使是支持它的系统,通常也是不一致的,例如commonjs https://nodejs.org/docs/latest/api/modules.html#modules_cycles会在一段时间内为您提供一个空对象。

Solution

Consider combining the two services into one. You can still move certain stuff (e.g. simple functions etc) out from the combined service if it becomes too much.

考虑将两种服务合二为一。如果组合服务变得太多,你仍然可以从组合服务中移出某些东西(例如简单的功能等)。

#3


2  

I agree with the solution proposed by basarat. Another workaround would be to initialize the instances outside DI and provide them as value like

我同意basarat提出的解决方案。另一种解决方法是初始化DI之外的实例并将它们作为值提供

One service needs to be modified to be able to create an instance without providing the other service as dependency:

需要修改一个服务才能创建实例而不将其他服务作为依赖项提供:

@Injectable()
export class FirstService {

  foo: string = 'abc';
  secondService: SecondService

  constructor() {
    //this.foo = this.foo + this.secondService.bar;
  }

  init(secondService:SecondService) {
    this.foo = this.foo + secondService.bar;
  }
}

Then create the instances imperatively and provide them as value

然后命令性地创建实例并将它们作为值提供

let firstService = new FirstService();
let secondService = new SecondService(firstService);

@Component({
  selector: 'my-app',
  template: '<h1>Hello world!</h1>',
  providers: [
    provide(FirstService, {useFactory: () => {
      firstService.init(secondService);
      return firstService;
  }}), provide(SecondService, {useValue: secondService})]
})
...

Plunker example

#1


3  

AngularJS does not allow injection of circular dependencies.

AngularJS不允许注入循环依赖项。

Miško Hevery, one of the authors of AngularJS, recommends finding the common elements:

AngularJS的作者之一MiškoHevery建议找到共同的元素:

+---------+      +---------+
|    A    |<-----|  B      |
|         |      |  |  +-+ |
|         |      |  +->|C| |
|         |------+---->| | |
|         |      |     +-+ |
+---------+      +---------+

And extracting it to a third service:

并将其提取到第三个服务:

                         +---------+
+---------+              |    B    |
|    A    |<-------------|         |
|         |              |         |
|         |    +---+     |         |
|         |--->| C |<----|         |
|         |    +---+     +---------+
+---------+

For more information, see Circular Dependency in constructors and Dependency Injection by Miško Hevery.

有关更多信息,请参阅MiškoHevery中的构造函数中的循环依赖关系和依赖关系注入。

#2


3  

I'm not an Angular expert so is it possible

我不是角色专家,所以有可能

No. Circular dependencies are not resolved by angular's DI.

不可以。通过角度的DI不能解决循环依赖关系。

Also even systems that do support it, quite commonly are inconsistent e.g. commonjs https://nodejs.org/docs/latest/api/modules.html#modules_cycles will give you an empty object for a while.

即使是支持它的系统,通常也是不一致的,例如commonjs https://nodejs.org/docs/latest/api/modules.html#modules_cycles会在一段时间内为您提供一个空对象。

Solution

Consider combining the two services into one. You can still move certain stuff (e.g. simple functions etc) out from the combined service if it becomes too much.

考虑将两种服务合二为一。如果组合服务变得太多,你仍然可以从组合服务中移出某些东西(例如简单的功能等)。

#3


2  

I agree with the solution proposed by basarat. Another workaround would be to initialize the instances outside DI and provide them as value like

我同意basarat提出的解决方案。另一种解决方法是初始化DI之外的实例并将它们作为值提供

One service needs to be modified to be able to create an instance without providing the other service as dependency:

需要修改一个服务才能创建实例而不将其他服务作为依赖项提供:

@Injectable()
export class FirstService {

  foo: string = 'abc';
  secondService: SecondService

  constructor() {
    //this.foo = this.foo + this.secondService.bar;
  }

  init(secondService:SecondService) {
    this.foo = this.foo + secondService.bar;
  }
}

Then create the instances imperatively and provide them as value

然后命令性地创建实例并将它们作为值提供

let firstService = new FirstService();
let secondService = new SecondService(firstService);

@Component({
  selector: 'my-app',
  template: '<h1>Hello world!</h1>',
  providers: [
    provide(FirstService, {useFactory: () => {
      firstService.init(secondService);
      return firstService;
  }}), provide(SecondService, {useValue: secondService})]
})
...

Plunker example