Angular функция зависит от результата asyn c функции - PullRequest
0 голосов
/ 28 мая 2020

Настройка:

У меня есть функция isAuthorized() в синглтоне AuthSessionSingleton, которая зависит от результата функции asyn c.

Asyn c функция - это вызов API, вызываемый в конструкторе, который ожидает возврата объекта . isAuthorized() полагается на этот объект .

Проблема:

Некоторые компоненты вызывают функцию isAuthorized() немедленно, до разрешения внутреннего вызова. Я хочу иметь возможность подождать внутри функции isAuthorized(), пока внутренний вызов не разрешится и объект перестанет быть нулевым.

Простой код:

//auth.singleton.ts
@Injectable({providedIn: 'root'})
export class AuthSessionSingleton {
  userInfo: UserInfo = null;
  constructor(private service: MyService) {
    this.loadUserInfo();
  }
  
  loadUserInfo() {
    this.service.makeBackendCall().subscribe({
      next: (obj: UserInfo) => {
        this.userInfo = obj;
      }
    });
  }
  
  isAuthorized() {
    if(this.userInfo == null) {
      // do something to wait asynchronously
    }

    // Very simple example
    if(this.userInfo.Role == 'Admin') {
      return true;
    }
    return false;
  }
}
//some.component.ts
export class SomeComponent {
  authorized: boolean = false;
  
  constructor(private auth: AuthSessionSingleton) {
    this.checkAuthorization();
  }
  
  async checkAuthorization() {
    this.authorized = await this.auth.isAuthorized();
  }
}

В приведенной выше упрощенной программе SomeComponent, вызывающий isAuthorized(), скорее всего, проверит userInfo, пока он все еще равен нулю. Мне нужно подождать, пока он не станет нулевым.

Возможные решения:

Я уже определил множество решений. Я ищу наиболее правильное решение и, надеюсь, такое, о котором я даже не подумал.

1. Слушайте подписку

В isAuthorized(), if(this.userInfo==null) подпишитесь на ту же подписку, сделанную в loadUserInfo(), и ждите ее.

2. Подождите, пока не поступит сигнал

Я мог бы создать Subject в AuthSessionSingleton и подписаться на SomeComponent, подождите, пока я не получу сигнал, затем позвоните IsAuthorized().

Это кажется особенно окольным .

3. Просто подождите

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

while(this.userInfo == null) {
  // do something
}

Запрос:

Мне нужен способ асинхронно ждать в isAuthorized() до this.userInfo != null. Любое количество вызовов может быть выполнено на isAuthorized() (от разных компонентов), и все они должны ждать, пока это значение не будет разрешено.

Есть идеи?

Edit

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

isAuthorized(roles: string[]) {
  let(i = 0; i < roles.length; i++) {
    let role = roles[i];
    if(this.userInfo.Role == role) {
      return true;
    }
    return false;
  }
}

Ответы [ 2 ]

1 голос
/ 28 мая 2020

Когда задействована одна асинхронная c операция, вы можете сделать все ее иждивенцы асинхронными. Попробуйте следующее

auth.singleton.ts

@Injectable({providedIn: 'root'})
export class AuthSessionSingleton {
  userInfo = new BehaviorSubject<UserInfo>(null);

  constructor(private service: MyService) {
    this.loadUserInfo();
  }

  loadUserInfo() {
    this.service.makeBackendCall().subscribe({
      next: (obj: UserInfo) => {
        this.userInfo.next(obj);
      }
    });
  }

  isAuthorized() {
    const result = new Subject<boolean>();

    this.userInfo.pipe(take(1)).subscribe(
      userInfo => {
        if (userInfo == 'Admin') {
          result.next(true);
        } else {
          result.next(false)
        }
      }
    );

    return result.asObservable();
}

Теперь вы можете подписаться на функцию isAuthorized() в компонентах. Вы также можете выставить userInfo для проверки авторизации в компоненте.

Компонент

ngOnInit() {
  this.authService.isAuthorized().subscribe(
    status => {
      if (status) {
        // authorized
      } else {
        // unauthorized
      }
    }
  );
}

Как упоминалось в комментариях, я бы не предпочел решения 1 и 2 для следующих причины

  1. Решение 1 : подписка может вызвать дополнительный нежелательный HTTP-запрос.
  2. Решение 3 : потенциально может привести к бесконечному l oop, если серверная часть не отвечает.
0 голосов
/ 28 мая 2020

Приведенный ниже код гарантирует, что ваше приложение инициализируется только после завершения loadUserInfo. Таким образом, другие компоненты будут вызывать isAuthenticated только тогда, когда приложение инициализируется и ваша информация пользователя уже существует.

В вашем AppModule есть это: -

{
      provide: APP_INITIALIZER,
      useFactory: init_app,
      deps: [AuthSessionSingleton],
      multi: true
 }

 export function init_app(authService: SessionService) {
  return () => authService.loadUserInfo();
 }

Измените свой AuthSessionSingleton: -

@Injectable({providedIn: 'root'})
export class AuthSessionSingleton {

  constructor(private service: MyService) {
  }

  loadUserInfo() {
    return this.service.makeBackendCall().pipe(map((obj: UserInfo) => {
        this.userInfo.next(obj);
    })).toPromise();
  }

   isAuthorized() {
      if(this.userInfo == null) {
          // do something to wait asynchronously
      }

      // Very simple example
      if(this.userInfo.Role == 'Admin') {
        return true;
      }
      return false;
   }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...