2016-11-21 4 views
0

У меня есть rxjs BehaviorSubject подписаться на использование async трубу от углового 2 и у меня есть catch для обработки возможных ошибок он бросает. Проблема в том, что каждый раз, когда я получаю сообщение об ошибке, он запускает бесконечный цикл, потому что мой улов возвращает Observable, полученный из BehaviorSubject, и я думаю, что труба async возвращается к наблюдаемому, когда я возвращаю catch.Бесконечный цикл при ловле ошибки от BehaviorSubject подписались асинхронном трубами на Angular 2

Код выглядит примерно так:

ListService - это @Injectable, где у меня есть BehaviorSubject и свойство с Observable.

private listSubject: BehaviorSubject<IItem[]>; 

public get listObservable() { 
    return this.listSubject.asObservable() 
} 

private error(error: IError) { 
    this.listSubject.error(error); 
} 

ListComponent - это @Component, который показывает список наблюдаемого.

// Template 
<items-view [items]="list | async"></items-view> 

// Code 
public get list() { 
    return this.listService.listObservable 
     .catch((error) => { 
      this.handleError(error); 
      return this.listService.listObservable; 
     }); 
} 

Как вы можете видеть, мой улов возвращает текущий наблюдаемый, поскольку он ДОЛЖЕН вернуть наблюдаемое. Итак, что происходит, когда я отправляю this.listSubject.error(error), код вводит бесконечный цикл, вызывающий catch бесконечно, потому что, как я уже говорил, я думаю, что BehaviourSubject повторно выбрасывает ошибку, потому что труба async повторно подписывается на наблюдаемую, когда catch возвращает его.

Я попытался вернуть свой предыдущий кешированный массив в ошибке, чтобы вернуть Observable.of(error.cached), но у меня возникло совершенно новое множество проблем, потому что думаю, что асинк не был подписан на BehaviorSubject.

Как я уже говорил, это грубое представление моего реального кода, но логика в основном такова.

Я пробовал разные подходы к этому, но мне не удалось остановить этот бесконечный цикл.

Заранее благодарим за помощь.

+0

Какова ошибка, которую вы получите, и что вы ожидаете от кода в случае ошибки? – KwintenP

+0

Любая ошибка, я передаю ошибку, используя эту функцию ошибки в службе List, даже если я просто передаю строку, у меня возникнет проблема. Но обычно я пропускаю ошибки ответа api. –

ответ

2

В общем, плохая идея вручную отправить сообщение об ошибке на тему, которая должна только выталкивать данные (например, BehaviorSubject в вашем случае). Причина в том, что при возникновении ошибки на SubjectSubject по существу dead -> означает, что новые данные не могут быть выброшены на него больше. Это одно из основных понятий rxjs. Вот небольшой пример:

let stream$ = new Rx.BehaviorSubject(1); 

stream$.subscribe(x => console.log("Logging: " + x), e => console.error("Error: " + e)); // logs 1, 2, Error: ... 

stream$.next(2); 
stream$.error(new Error("Some error message.")); 
stream$.next(3); // this will have no effect, because the stream is "dead" 
stream$.subscribe(x => console.log("Logging 2: " + x), e => console.error("Error: " + e)); // this will just log the error 

В вашем случае это означает, что вы сделали некоторые обработки ошибок, но потом просто вернуть «старый, мертвый, ошибка» -subject - другими словами: распространять ошибку вниз по поток. (Я не предполагая, что handleError() создает свежий Subject, который был бы ужасной практикой в ​​любом случае.)

В общем случае это означает, что .error следует использовать только для потоков, которые выполняют определенную операцию и имеют определенное количество результатов а затем заполнить или выбросить ошибку, но не на Subject s, которые вы хотите испускать данные на протяжении всего срока службы приложения.

Как это решить в вашем случае: Быстрое & грязное (действительно грязное !!) было бы использовать два отдельных объекта, один для данных и один для ошибок (выброс с .next).

Правильное исправление: Разделите свою архитектуру на поток данных и в хранилище данных.

Жизненный цикл будет выглядеть примерно так:

Generative Flow

  1. Некоторые события (например кнопка-Click, или некоторые Timebased Event)
  2. Service.generateOrFetchData() handleErrors.()
  3. StoreService.someSubj.next (данные) - (шаг 3 может быть дополнительным, в зависимости от того, как вы хотите обрабатывать ошибки на шаге 2)

Подписавшись Flow

  1. UI Присоединяется к StoreService.someSubj
  2. UI автоматически обновляется каждый раз, когда новые данные выбрасываются, не обработки ошибок не требуется

идеально исправить было бы использование готовой к использованию продуманной архитектуры хранилища, такой как ngrx, однако реализация этого в существующем проекте будет связана с основными требованиями рефакторинга.

+0

Да, теперь я пошел с грязным исправлением, я вернусь к этому, когда закончу то, что я делаю в данный момент. –