Индикатор загрузки по Http запросам

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

getMyHttpObservable(...) {
    setLoadingIndicator(true);
    const myHttpObservable = 
        createRequestObservable().finally(()=> {
            console.log('http done');
            setLoadingIndicator(false);
        });
    return myHttpObservable;
}

У меня есть последовательность наблюдаемых, которые я связываю с помощью Observable.concat следующим образом:

const t1 = Observable.timer(5000).finally(()=>console.log('t1 done'));
const t2 = getMyHttpObservable(...);
const agg = Observable.concat(t1,t2);

Я использую метод отмены на основе событий, используя Observable.takeUntil следующим образом:

const ev = new EventEmitter<any>();
const cancellableAgg = agg.takeUntil(ev.asObservable());

Теперь проблема в том, что когда я отменяю агрегатное наблюдаемое в течение первого периода таймера, я не получаю окончательный вызов второго наблюдаемого - http-запрос. Пример:

const cancel = Observable.timer(500).finally(()=>ev.emit());
cancellableAgg.subscribe();
cancel.subscribe();

Когда вышеприведенное выполняется, я получаю этот вывод:

t1 done

И мне нужно получить еще и http done, чтобы индикатор загрузки был очищен. Как я могу этого добиться?

Спасибо!

ИЗМЕНИТЬ

Я не понял, что оператор concat подписывается на наблюдаемые только после завершения их предшественников. Что мне нужно, так это активировать мой индикатор загрузки только тогда, когда наблюдаемый http действительно подписан.

Я изменил свою функцию-оболочку следующим образом:

getMyHttpObservable(...) {
    const myHttpObservable = createRequestObservable(...);
    const subscriptionAware = new Observable(subscriber => {
        setLoadingIndicator(true);
        myHttpObservable.subscribe(
            nextEv => subscriber.next(nextEv),
            errEv => subscriber.error(errEv),
            () => subscriber.complete())
        .add(()=>setLoadingIndicator(false));
    };
    return subscriptionAware;
}

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

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

Любые идеи о том, как этого добиться?


person Aviad P.    schedule 28.08.2016    source источник
comment
Я бы предложил другой подход, заключающийся в определении декоратора для применения к методам, в которых вы хотите установить счетчик. Размещение счетчика на уровне http недостаточно гибко и ИМХО путает сетевую логику с пользовательским интерфейсом.   -  person    schedule 28.08.2016


Ответы (1)


Удалось найти решение, используя встроенный оператор defer, который ожидает подписки и возвращает новый наблюдаемый объект:

getMyHttpObservable(...) {
    const myHttpObservable = createRequestObservable(...);
    return Observable.defer(() => {
        setLoadingIndicator(true);
        return myHttpObservable.finally(() => setLoadingIndicator(false));
    });
}

Элегантный и короткий.

person Aviad P.    schedule 30.08.2016