Angular 5 - как ждать возврата значения из асинхронного метода - PullRequest
0 голосов
/ 08 июня 2018

Мой ngOnInit метод моего корня AppComponent выполняет некоторую аутентификацию следующим образом:

  token: SessionToken;
  authenticated: boolean;

  constructor(
    private authService: AuthenticationService,
    private router: Router) {}

ngOnInit() {
    this.authService.authenticate().subscribe(token => {
      if (token != null) {
        // authenticated
        this.token = token;
        this.authenticated = true;
      } else {
        // not authenticated
        this.authenticated = false;
      }
    });
  }

Вот мой authenticate метод в authService:

// Authenticate user. Returns non-null token if authenticated, null token otherwise. 

  token: MyCustomToken;

  authenticate(): Observable<MyCustomToken> {
    return this.http.get<SessionToken>(this.url)
      .pipe(
        tap(token => this.token = token),
        catchError(this.handleError<SessionToken>('authenticate'))
      );
  } 

Затем в той же службе у меня также есть другой метод, который проверяет, прошел ли пользователь проверку подлинности, проверяя, был ли токен, возвращенный из вызова authenticate, нулевым или нет:

public isAuthenticated(): boolean {
    if (this.token != null) {
      return true;
    } else {
      return false;
    }
  }

Наконец,в моем методе canActivate моего охранника аутентификации я хочу вызвать этот метод isAuthenticated, чтобы проверить, прошел ли аутентификация пользователя перед отображением страницы:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean>|boolean {
        console.log("in canActivate() of authentication guard."); 

        let val = this.authService.isAuthenticated();
        console.log(`Is authenticated? ${val}`); // printing false, even though the server returned a non-null token when I called authenticate in AppComponent
        return val;
}

Проблема в том, что this.authService.isAuthenticated() вcanActivate метод возвращает false, даже если сервер возвратил ненулевой токен, когда я вызвал authenticate в AppComponent.

Кажется, что происходит canActivate вызывается до токен возвращается с сервера при вызове authenticate в AppComponent, потому что authenticate является асинхронным вызовом.

Так есть ли способ подождать, покаасинхронный вызов для завершения или какой-либо другойобходной путь?

1 Ответ

0 голосов
/ 08 июня 2018

Вот "псевдо" код , который должен помочь вам в том, как написать некоторые методы цикла запуска, включающие много асинхронных операций.Этот обычно живет в app.component.ts.

В этом ниже также предполагается, что ваше приложение имеет некоторую форму локального сохранения (библиотека, такая как localForage и т. Д., Которая абстрагирует и облегчает доступ к сохранению indexeddb или websql на клиенте).

Локальное сохранениеважно помочь хранить контекстные данные пользователя (например, показывалось ли вступление и т. д.), который используется для определения цикла запуска:

  initApp() {
    // this below collects all locally persistent data about user:
    this.getAppContext().then(()=>{
      // here some additional activities depending on your app:
      this.statusBar.hide();
      this.splashScreen.hide();
      // then we proceed with startup cycle:
      this.startUpCycle();
    })
  }

  // gather application context: userData, appIsOnline, JWT token, appIsCordova etc
  async getAppContext() {
    // foundation here is a global service that is available across the app:
    const promise = await this.foundation.storage.get("___userData")
    if (promise) {
      this.foundation.userData = promise;
      this.foundation.userID = promise.user._id;
      this.foundation.introShown - promise.introShown;
      this.foundation.appHasUserData = true;
    } else {
      this.foundation.appHasUserData = false;
    }
  };

  startUpCycle() {
  // if no data stored locally - we direct user to signup / intro page:
  if (!this.foundation.appHasUserData) {
      set signup page as the root page
      END
      // if data was persisted before:
  } else {
      (initalize local storage with user data).then(() => {
        (load additional user data like documents etc).then(() => {
          (check JWT as part of this.foundation.userData).subscribe(() => {
            do stuff
          set root page as the main page
            initialise FCM / notifications
            sync to remote database
          }, (err) => {
            set root page to login page
          })
        }
      })
    })
  }

Также в идеале я бы рекомендовал составить диаграмму, которая имеет логику того, что и в какомпорядок должен произойти в вашем приложении, прежде чем писать код.Пример (его приложение Ionic / Angular, которое может быть в автономном режиме, а также на Cordova / native);

enter image description here

...