Вложенные наблюдаемые и смешанные обещания - PullRequest
0 голосов
/ 08 мая 2019

У меня есть приложение Angular 7, которое общается с бэкэндом Firestore.

Я все еще пытаюсь обернуть голову Обещаниям против Наблюдаемых из-за асинхронной обработки.

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

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

Да, я, вероятно, должен денормализовать данные.

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

  checkGroupPermission(groupId: string, permissionName: string): any {
    this.userService.getCurrentUser().then(user => {
      this.userService.getUserForFirebaseUid(user.uid).subscribe(users => {
        if (users.length === 0) { return false; }
        this.groupUsersService.getAllForUser(users[0].id).subscribe(groupUsers => {
          const groupUser = groupUsers.find(cu => cu.groupId === groupId);
          this.roleService.getRole(groupUser.roleId).subscribe(role => {
            this.rolePermissionService.getRolePermissionsForRoleId(role.id).subscribe(rolePermissions => {
              this.permissionService.getPermissionByName(permissionName).subscribe(permissions => {
                if (permissions.length === 0) { return false; }
                const rolePermission = rolePermissions.find(rp => rp.permissionId === permissions[0].id);
                if (rolePermission) {
                  return true;
                } else {
                  return false;
                }
              });
            });
          });
        });
      });
    });
  }

У меня также есть около пяти разных разрешений для проверки.Я хочу привести это в порядок и взглянуть на Promises vs Observables.

checkSomething(): Promise<boolean> {
  return this.myService.getData().then(data => {
    return true;
  }, reason => {
    return false;
  });
}

subCheckOfSomething(): Observable<boolean> {
  return this.myService.getFirebaseSubscribe().pipe(map(dataArray => {
    if (dataArray.length > 0) {
      return true;
    } else {
      return false;
    }
  }));
}

Две функции по отдельности в порядке, но если я попытаюсь вызвать одну из другой:

checkSomething(): Promise<boolean> {
  return this.myService.getData().then(data => {
    this.subCheckOfSomething().subscribe(data => { return data; });
  }, reason => {
    return false;
  });
}

не работает, потому что Observable не является Обещанием

Я знаю, что мог бы переписать subCheckOfSomething, чтобы вместо этого вернуть Обещание:

subCheckOfSomething(): Promise<boolean> {
  return new Promise(resolve,reject) => {
  const data = this.myService.getFirebaseSubscribe().pipe(map(dataArray => {
    if (dataArray.length > 0) {
      return true;
    } else {
      return false;
    }
  }));
  data.subscribe(result => {
      resolve(result);
  }, err => {
      reject(err); })
  });
}

Но это не лучшее решение,Есть ли какие-либо предпочтительные способы обработки сценариев, как этот?

1 Ответ

1 голос
/ 08 мая 2019

Использование обещаний

RxJs имеет toPromise -метод, который вы можете использовать для возврата обещания. Обещание будет преобразовано в значение последнего испущенного значения наблюдаемого, как только оно завершится.

subCheckOfSomething(): Promise<boolean> {
  return this.myService.getFirebaseSubscribe().pipe(map(dataArray => {
    if (dataArray.length > 0) {
      return true;
    } else {
      return false;
    }
  }))
  .toPromise();
}

Использование наблюдаемых

Проблема в том, что вы не можете рано выйти из наблюдаемой цепочки (вы могли бы взломать и выбросить ошибку и поймать ее в конце, но я думаю, что это не рекомендуется), поэтому у вас есть эти вложенные наблюдаемые подписки. Как вы упомянули, вы должны привести это в порядок несколькими способами. Вам также нужно подписаться только один раз в самом конце, и вы можете передать остальные ваши методы следующим образом:

  checkGroupPermission(groupId: string, permissionName: string): Observable<boolean> {
    this.userService.getCurrentUser().pipe(
      switchMap(user => {
      this.userService.getUserForFirebaseUid(user.uid).pipe(
        switchMap(users => 
          if (users.length === 0) { return of(false); }
          return this.groupUsersService.getAllForUser(users[0].id).pipe(
           switchMap(groupUsers => {
           // Basically you replace subscribe with pipe(switchMap())
        })
      })
    );
  }

Лично я думаю, что в определенных частях вашего заявления можно иметь обещания. Мне кажется, что этот файл наиболее удобен для чтения с async / await (без использования .then), так что пока вам не нужны дополнительные функции, такие как «прервать эту проверку и начать новую» (switchMap было бы здорово для этого) я был бы в порядке с этим. Кроме того, вы можете легко перевести одно на другое, используя toPromise (rxjs-> обещание) или статический rxjs-оператор from (обещание-> rxjs).

...