Подтвердить что ты не робот

Услуги в зависимости друг от друга

В моем приложении Angular 2 у меня есть два сервиса, которые зависят друг от друга (сервис A вызывает методы из сервиса B и наоборот).

Вот соответствующий код:

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) {}
}

Запуск приложения приводит к следующей ошибке:

ИСКЛЮЧЕНИЕ: не удается разрешить все параметры для Temp2Service (не определено). Убедитесь, что все параметры оформлены с помощью Inject или имеют допустимые аннотации типов, а Temp2Service - с Injectable.

При комментировании конструктора в одном из сервисов приложение работает нормально. Поэтому я предполагаю, что проблема заключается в "перекрестной ссылке" двух сервисов.

У вас есть идея, что здесь происходит не так? Или мой подход уже неправильный?

4b9b3361

Ответ 1

Это называется круговой зависимостью. Это не проблема с самим Angular2. Это не разрешено ни на одном из известных мне языков.

Вам нужно будет реорганизовать свой код, чтобы удалить эту циклическую зависимость. Скорее всего, вам нужно будет разбить один из этих сервисов на новый сервис.

Если вы будете следовать принципу единой ответственности, вы обнаружите, что не попадете в круговую ловушку зависимости.

Ответ 2

Встраивание конструктора предотвращает циклические зависимости.

Его можно разбить, введя Injector и запросив зависимость зависимым образом:

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

См. также Циклическая зависимость angular 2

Ответ 3

Ключевым моментом здесь является не внедрение службы через конструктор, а использование явных сеттеров и геттеров. Я бы использовал следующий шаблон в 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;
    }

}

Ответ 4

В документации Angular 2 о циклической зависимости есть глава. Я думаю, что это очень полезно.

Включение зависимостей

Ответ 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();
  }
}

Ответ 6

Это круговая зависимость и, к сожалению, это фундаментальная проблема информатики или информационная проблема, которую Angular не может решить. Попробуйте сделать что-то вроде этого:

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

export class ServiceB {

 private a: ServiceA

 constructor(){

 }

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

}

это, вероятно, лучший способ сделать это.

Ответ 7

вы можете попытаться позвонить NEW по одной из служб, если не имеет однотональное значение. как

this._sessionService = new TempService(this);

Это был подход, который я использовал, поскольку ни одна из служб не использовала переменные-члены undefined.

Ответ 8

Если вы используете Angular 2 и нуждаетесь в циклической зависимости для вызова функций друг от друга на некоторых событиях, вы можете использовать Observables и подписываться на них в службе, в которую вы ввели другую службу.

Маленький пример: -

@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]();
});
   }
}

Ответ 9

Мы можем решить функцию forwordRef для решения этой проблемы.

//Позволяет ссылаться на ссылки, которые еще не определены.

@Inject (forwardRef (() = > MyService)) private httpProxy: MyService

Ответ 11

Все, что я пытался исправить предупреждением о циклической зависимости с помощью setTimeout или использованием инжектора и перемещением инъекции из конструктора в другую функцию, не работало для меня с angular 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;
  }
  ...
}