Подписка на обещание - PullRequest
0 голосов
/ 09 апреля 2019

В моем приложении Angular 7 у меня есть следующая функция:

  getUserData(uid) {
    return this.fireStore.collection('users').doc(uid).valueChanges().subscribe(data => {
      this.writeCookie(data)
      this.currentUser = data;
    })
  }

И я хочу использовать эту функцию внутри другого метода:

   someMethod() {
      ...
      new Promise(this.getUserData(uid))
         .then(() => {...})
      ...
   }

Но я не могу этого сделать,потому что TypeScript выдает ошибку:

Аргумент типа 'Подписка' не может быть назначен параметру типа '(resol: (value ?: {} | PromiseLike <{}>) => void, reject: (причина ?: любая) => void) => void '.Тип «Подписка» не обеспечивает совпадения для подписи »(resol: (value ?: {} | PromiseLike <{}>) => void, reject: (причина ?: любая) => void): void'.ts (2345)

Как преобразовать метод getUserData() в обещание или использовать вместо него forJoin?

Заранее спасибо.

Ответы [ 3 ]

1 голос
/ 09 апреля 2019

subscribe изменяет тип с Observable на Subscription, вызывая ошибку типа.

Что вам, вероятно, нужно, это преобразовать Observable в Promise, сохранив при этом вызов функции.Вы можете сделать это, пропустив Наблюдаемое через tap, а затем преобразовав результат в toPromise.Например:

getUserData(uid) {
  return this.fireStore.collection('users').doc(uid).valueChanges().pipe(
    tap(data => {
      this.writeCookie(data)
      this.currentUser = data;
    }),
    first()
  ).toPromise()
}

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

Вы можете опустить new Promise(...) у вашего потребителя.

0 голосов
/ 10 апреля 2019

Реализация ggradnig - правильное решение, однако я бы хотел более подробно проанализировать ПОЧЕМУ это работает, чтобы не было путаницы, если кто-нибудь столкнется с этой проблемой в будущем.

Когда вы подписываетесь на наблюдаемое, большую часть времени вы передаете только одну функцию обратного вызова, которая описывает, как вы хотите обрабатывать данные из потока при его получении. В действительности, хотя есть 3 различных обратных вызова, которые могут быть включены в наблюдателя для различных типов событий. Это:

  1. next - Вызывается при получении данных из потока. Так что, если вы делаете запрос на получение статистики покемонов, он собирается вызвать функцию «следующего» обратного вызова и передать эти данные как вход. В большинстве случаев это единственные данные, которые вас интересуют, и Создатели rxjs знали об этом, поэтому, если вы включите только 1 обратный вызов функция в подписке, подписка будет по умолчанию передача «следующих» данных в этот обратный вызов.

  2. ошибка - Довольно понятно. Если в вашу наблюдаемую ошибку не попадает ошибка, она вызывает этот обратный вызов.

  3. complete - Вызывается, когда наблюдаемое завершается.

Если вы хотите иметь дело со всеми различными типами данных, генерируемых наблюдаемой, вы можете написать в своей подписке наблюдателя, который будет выглядеть примерно так:

this.http.get(“https://pokemon.com/stats/bulbasaur”).subscribe({
    next: () => { /* deal with pokemon data here */},
    error: () => {/* called when there are errors */},
    complete: () => {/* called when observable is done */}
})

Опять же, в большинстве случаев это не нужно, но важно понимать эти типы событий, когда мы вызываем метод .toPromise () в Observable. Когда мы конвертируем Observable в Promise, происходит то, что Promise собирается разрешить с последними «следующими» данными, полученными из Observable, как только будет вызван метод «Complete» в Observable. Это означает, что, если «Полный» обратный вызов не вызван, Обещание будет зависать бесконечно.

Да, я знаю, о чем вы думаете: я постоянно преобразую свои http-запросы из Observables в Promises, и я никогда не сталкиваюсь с ситуацией, когда мое Promise зависает бесконечно. Это потому, что угловая http-библиотека вызывает «завершенный» обратный вызов в Observable, как только все данные получены из http-вызова. Это имеет смысл, потому что, как только вы получите все данные из запроса, вы закончите. Вы не ожидаете больше данных в будущем.

Это отличается от ситуации, описанной в вопросе, когда вы звоните в пожарный магазин, и, как я знаю по опыту, для передачи информации используются сокеты, а не запросы http. Это означает, что через соединение вы можете получить начальный набор данных ... и затем больше данных ... и затем больше данных. По сути, это поток, который не имеет определенного конца, поэтому у него никогда нет причин вызывать «полный» обратный вызов. То же самое произойдет с предметами Поведение и Повтор.

Чтобы обойти эту проблему, вы должны заставить Observable вызвать обратный вызов «Complete», либо добавив «first ()» или «take (1)», что будет делать то же самое, вызовите функцию обратного вызова «next» с исходным набором данных в качестве входных данных, а затем вызовите обратный вызов «Complete».

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

Также это видео является отличным справочником, если вы все еще не уверены: https://www.youtube.com/watch?v=Tux1nhBPl_w

0 голосов
/ 09 апреля 2019

В настоящее время вы возвращаете всю подписку.Чтобы это исправить, вам нужно использовать toPromise

getUserData(uid) {
        return this.fireStore.collection('users').doc(uid).valueChanges().toPromise()
      }

Поскольку вы возвращаете обещание в указанном выше поле, не нужно создавать новое обещание

   someMethod() {
      ...
      this.getUserData(uid)
         .then(() => {...})
      ...
   }
...