Подпишитесь на http.post это место внутри обещания Angular 6

1

Мне становится сложно, когда я смешиваю обещание с подпиской и другой задачей асинхронного взаимодействия.

Это моя служба авторизации:

getCurrentUserToken(){
    return new Promise((resolve,reject)=>{
      firebase.auth().currentUser.getIdToken(/* forceRefresh */ true).then(function(idToken) {
        resolve(idToken)
      }).catch(function(error) {
        reject(error)
      });
    }) 
  }

Это мой сервис http:

sendEmail(email) {

    return this.authService.getCurrentUserToken().then(token => {
      const httpOptions = {
        headers: new HttpHeaders({
          'Content-Type': 'application/json',
          'Authorization': 'Basic server-Password',
        })
      };
      let data = email
      data['idToken'] = token
      return this.http.post(this.apiServer + 'sendEmail', data, httpOptions)
    })

  }

Вот как я вызываю sendEmail(email) в компоненте:

    Observable.fromPromise(this.httpService.sendEmail(element)).subscribe(
      data3 => {
        console.log(data3)

      }, error => {
        console.log(error)
      }
    ))

Мне нужно передать currentUserToken в API, чтобы API аутентифицировал пользовательский сеанс, но оба метода getCurrentUserToken() sendEmail() выполняются в async, поэтому я должен использовать Promise для передачи функции Token to sendEmail() и пусть функция sendEmail вызывает API для отправки электронной почты.

Без обещания я могу подписаться на http.post следующим образом:

this.httpService.sendEmail(element).subscribe(
          data3 => {
            console.log(data3)

          }, error => {
            console.log(error)
          }
        ))

К сожалению, я ввернул его, когда добавил в него обещание, и console.log возвращает это: Observable {_isScalar: false, source: Observable, operator: MapOperator}

Пожалуйста, сообщите, как подписаться на http.post который размещается внутри Promise.

Теги:
angular
rxjs
firebase-authentication
observable

2 ответа

2
Лучший ответ

Здесь серьезно не нужно усложнять ситуацию.

Здесь я буду использовать синтаксис async/await и для этого нам придется работать с Promise вместо Observable s. Хорошо, мы можем использовать метод toPromise() для значения Observable чтобы изменить его на Promise

Сосредоточьтесь также на моих комментариях в коде

Здесь реализация

Для getCurrentUserToken

getCurrentUserToken() {
  return firebase.auth().currentUser.getIdToken(true);
  // This will already return a Promise<string>
  // So no need to do a .then and then return from there.
}

Для sendEmail

async sendEmail(email) {
  // Since getCurrentUserToken returns a Promise<string> we can await it
  const token = await this.authService.getCurrentUserToken();
  // token will now have the Current User Token
  const httpOptions = {
    headers: new HttpHeaders({
      'Content-Type': 'application/json',
      'Authorization': 'Basic server-Password',
    })
  };
  let data = email
  data['idToken'] = token
  return this.http.post(this.apiServer + 'sendEmail', data, httpOptions).toPromise();
  // Notice how we're calling the .toPromise() method here 
  // to change Observable into a Promise
}

Как это использовать?

Этот код пойдет в вашем Component Method, где вы ранее this.httpService.sendEmail. УБЕДИТЕСЬ, ЧТОБЫ ОЗНАКОМИТЬСЯ, ЧТО ФУНКЦИЯ AS async МЫСЛЬ.

// We can only await something in a function which is declared of type async
async sendEmail() {
  try {
    const data = await this.httpService.sendEmail(element);
    // Since sendEmail again returns a Promise, I can await it.
    console.log(data);
  } catch (error) {
    console.log(error);
  }
}
  • 0
    Спасибо за ответ. Но у меня есть вопрос в заключительной части. Должен ли я обернуть весь try catch другим асинхронным кодом или try catch является оболочкой для await sendEmail() ?
  • 1
    Я обновил свой ответ, чтобы уточнить ваши сомнения. Пожалуйста, посмотрите.
Показать ещё 1 комментарий
0

Почему бы нам не использовать Observable вместо Promises.



    getCurrentUserToken() {
    return new Observable(obs => {
      firebase
        .auth()
        .currentUser.getIdToken(/* forceRefresh */ true)
        .then(function(idToken) {
          obs.next(idToken);
          obs.complete();
        })
        .catch(function(error) {
          obs.error(error);
        });
     });
    }

    sendEmail(email): Observable {
     return new Observable(obs => {
      this.authService.getCurrentUserToken().subscribe(token => {
        const httpOptions = {
          headers: new HttpHeaders({
            'Content-Type': 'application/json',
            Authorization: 'Basic server-Password'
          })
        };
        let data = email;
        data['idToken'] = token;
        this.http
          .post(this.apiServer + 'sendEmail', data, httpOptions)
          .subscribe(
            result => {
              obs.next(result);
              obs.complete();
            },
            error => {
              obs.error();
            }
          );
      });
     });
    }

     // now call the service from Component like this.
     this.httpService.sendEmail(element).subscribe(
      data3 => {
        console.log(data3)

      }, error => {
        console.log(error)
      }
     ));

  • 2
    subscribe внутри subscribe - это анти-шаблон, называемый «адом обратного вызова», вы можете использовать операторы выравнивания, такие как switchMap / mergeMap чтобы решить эту проблему

Ещё вопросы

Сообщество Overcoder
Наверх
Меню