Loading indicator on Http requests

三世轮回 提交于 2020-01-15 02:37:28

问题


The root of my problem is displaying a loading indicator on http requests, and I want to do it at the service level without having to write code for each component. What I did was implement an http wrapper that basically does this:

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

I have a sequence of observables which I chain using Observable.concat as follows:

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

I am using an event based cancellation technique using Observable.takeUntil as follows:

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

Now the problem is when I cancel the aggregate observable during the first timer period I do not get the finally call of the 2nd observable - the http request. Example:

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

When the above runs, I get this output:

t1 done

And I need to get http done as well, so that the loading indicator is cleared. How can I achieve that?

Thanks!

EDIT

I failed to realize that the concat operator only subscribes to observables down the line, when their predecessors have completed. What I need is to activate my loading indicator only when the http observable has actually been subscribed to.

I modified my wrapper function as follows:

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;
}

So basically, I'm creating an Observable which transparently wraps another Observable, but also performs some additional actions when it's actually subscribed to - activate the loading indicator.

However, now I've lost the ability to cancel XHR requests in flight, since the constructor of Observable doesn't allow me to pass a handler for cancellation, so the inner subscription will never get cancelled.

Any ideas as to how to achieve that?


回答1:


Managed to find a solution using the built in defer operator which waits for a subscription and returns a fresh observable:

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

Elegant and short.



来源:https://stackoverflow.com/questions/39190672/loading-indicator-on-http-requests

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!