Асинхронная инициализация службы Angular 2

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

@Injectable()
export class Api {
    private user;
    private storage;

    constructor(private http: Http) {
        this.storage = LocalStorage;
        this.storage.get('user').then(json => {
            if (json !== "") {
                this.user = JSON.parse(json);
            }
        });        
    }

    // one of many methods
    public getSomethingFromServer() {
        // make a http request that depends on this.user
    }
}

В настоящее время эта служба инициализируется и немедленно возвращается к любому компоненту, который ее использует. Затем этот компонент вызывает getSomethingFromServer() в своем ngOnInit, но в этот момент Api.user не инициализируется, и поэтому отправляется неправильный запрос.

Крюки жизненного цикла (OnInit, OnActivate и т.д.) не работают с сервисами, а только с компонентами и директивами, поэтому я не могу их использовать.

Для сохранения обещания из get() для вызова потребуется все различные методы, зависящие от пользователя, чтобы ждать его, что вызывает много дублирования кода.

Каков рекомендуемый способ инициализации служб async в Angular 2?

Ответы

Ответ 1

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

@Injectable()
export class Api {
  private userPromise: Promise<User>;

  constructor(private http: Http) {
    this.userPromise = LocalStorage.get('user').then(json => {
      if (json !== "") {
        return JSON.parse(json);
      }
      return null;
    });        
  }

  public getSomethingFromServer() {
      return Observable.fromPromise(this.userPromise).flatMap((user) => {
        return this.http.get(...).map(...);
      });
    }
  }
}

Это гарантирует, что функция flatMap получает пользователя каждый раз, когда он вызывается, а не только в первый раз, как в ответе Тьерри.

Ответ 2

Вы можете использовать наблюдаемый для этого оператор flatMap. Если пользователя нет, вы можете подождать его и затем связать целевой запрос.

Вот пример:

@Injectable()
export class Api {
  private user;
  private storage;
  private userInitialized = new Subject();

  constructor(private http: Http) {
    this.storage = LocalStorage;
    this.storage.get('user').then(json => {
      if (json !== "") {
        this.user = JSON.parse(json);
        this.userInitialized.next(this.user);
      }
    });        
  }

  // one of many methods
  public getSomethingFromServer(): Observable<...> {
    // make a http request that depends on this.user
    if (this.user) {
      return this.http.get(...).map(...);
    } else {
      return this.userInitialized.flatMap((user) => {
        return this.http.get(...).map(...);
      });
    }
  }
}