Angular 6 / Rxjs - основы: наблюдаемые успехи, ошибки, наконец - PullRequest
0 голосов
/ 28 июня 2018

Я строю архитектуру на последней версии Angular 6 и, исходя из AngularJS, есть кое-что, о чем я не могу смириться: базовая обработка HTTP-запроса.

Итак, ради вопроса, допустим, я хочу наблюдаемого. Потому что это похоже на будущее Angular.

Я вышел из чего-то очень элегантного в AngularJS:

   service.getAll()
    .then(onSuccess) // I process the data
    .catch(onError) // I do whatever needed to notify anyone about the issue
    .finally(onFinally); // I stop the loading spinner and other stuff

Теперь в Angular 6 / RxJS 6 я не понимаю, почему все так сложно и выглядит не так.

Я мог бы найти два способа сделать то же самое, что и выше:

  1. Полная труба

    this.service.getAll()
        .pipe(
            map((data) => this.onSuccess(data)),
            catchError(error => of(this.handleError(error))),
            finalize(() => this.stopLoading())
        )
        .subscribe();
    

Поскольку нам нужно использовать pipe для финализации, я мог бы также использовать pipe для всего, я думаю, что лучше практиковать, чтобы все было в одном и том же порядке. Но теперь мы должны выбросить что-то, называемое «о» (не очень легко понять), и мне это не нравится.

  1. Половина трубы Поэтому я пробую другую идею, используя только нужную мне трубу (финализирую) и сохраняю обратные вызовы подписки.

    this.service.getAll()
    .pipe(
        finalize(() => this.stopLoading())
    )
    .subscribe(
        (data) => this.onSuccess(data),
        (error) => this.handleError(error)
    );
    

Но, хорошо. Разве это не немного отсталый? У нас все еще есть обратные вызовы без реальных имен, и мы завершаем работу перед чтением обработки и ошибки. Weird.

Так что есть кое-что, что я определенно не понимаю. И я не могу найти ничего связанного с этим основным вопросом онлайн. У вас есть кто-то, кто хочет «успех и наконец», или «успех и ошибка», но никто не хочет 3 из них. Может быть, я слишком стар, и я не понимаю новую лучшую практику об этом (если так, пожалуйста, обучите меня!).

Моя потребность проста:
1. Я хочу обработать данные, полученные от службы
2. Я хочу получить ошибку для отображения пользователю
3. Я хочу остановить загрузочный счетчик, который я только что начал перед вызовом, или сделать еще один вызов, если первый вызов завершился успешно или произошла ошибка (я действительно хочу окончательно)

Как вы справляетесь с вашим базовым HTTP-вызовом с помощью наблюдаемого?

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

Ответы [ 3 ]

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

Я думаю, что правильный способ - использовать наблюдаемые функции: далее, ошибаться, завершить.
Вот пример того, как вы можете вызвать полную функцию.
Допустим, у нас есть объект BehaviorSubject:

let arr = new BehaviorSubject<any>([1,2]);

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

let arrSubscription = arr.asObservable().subscribe(
  data => {
      console.log(data)
      if(data === 'finish') {
        arr.complete()
      }
  },
  err => {
      console.log(err)
  },
  () => {
      console.log("Complete function triggered.")
  }
);
arr.next([3,4])
arr.next('finish')
arr.next([5,6])

Журнал консоли:

[1,2]
[3,4]
finish
Complete function triggered.

Поскольку мы запустили полную функцию, последний .next к нашему объекту BehaviorSubject не сработал, поскольку err и полная функция являются терминаторами подписки.
Это всего лишь пример того, как вы можете запустить полную функцию, отсюда вы можете делать все, что захотите.

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

Я думаю, что есть одно ключевое недоразумение:

У вас есть кто-то, кто хочет «успеха и наконец», или «успеха и ошибки», но никто не хочет 3 из них.

Это не совсем так. Каждый Observable может отправлять ноль или более next уведомлений и одно error или complete уведомлений, но не оба одновременно. Например, при успешном вызове HTTP у вас будет одно next и одно complete уведомление. При ошибке HTTP-запроса у вас будет только одно error уведомление и все. См http://reactivex.io/documentation/contract.html

Это означает, что у вас никогда не будет наблюдаемого, испускающего и error, и complete.

И еще есть оператор finalize. Этот оператор вызывается при утилизации цепочки (которая также включает в себя обычную отписку). Другими словами, он называется после и error и complete уведомлений.

Итак, второй пример, который у вас есть, правильный. Я понимаю, что выглядит странно, что вы включаете finalize перед подпиской, но на самом деле каждый выброс из источника Observable идет сначала сверху вниз, где он достигает подписчиков, и там, если его уведомление error или complete вызывает срабатывание обработчиков снизу вверх (в обратном порядке) и в этот момент вызывается finalize. См https://github.com/ReactiveX/rxjs/blob/master/src/internal/Subscriber.ts#L150-L152

В вашем примере использование finalize аналогично добавлению обработчика утилизации в Subscription объекты.

const subscription = this.service.getAll()
  .subscribe(
    (data) => this.onSuccess(data),
    (error) => this.handleError(error)
  );

subscription.add(() => this.stopLoading());
0 голосов
/ 28 июня 2018

Метод subscribe Observable принимает 3 необязательные функции в качестве параметров

  • первый обработчик данных, которые приходят с событием, вызванным Наблюдаемый
  • второй обработчик любой ошибки, если она возникла
  • третий, кто что-то делает по завершении Наблюдения

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

this.service.getAll()
.subscribe(
    data => this.onSuccess(data),
    error => this.handleError(error),
    () => this.onComplete()
);

Учтите, что использование Observables для вызовов http может дать преимущества, если вы хотите повторить попытку (см. Оператор retry), если у вас есть условия гонки (с помощью оператора switchMap). Я думаю, что это основные причины, по которым команда Angular выбрала этот подход для http-клиента.

Вообще говоря, я думаю, что стоит начать знать, как работают Observables и некоторые из наиболее важных операторов (в дополнение к вышеприведенным, я думаю сначала о mergeMap, filter, reduce - но потом многие другие) важны, поскольку они могут значительно упростить многие задачи в асинхронных неблокирующих средах, таких как браузер (или, например, Node).

...