Angular2:switchMap不取消之前的http调用

问题描述 投票:14回答:4

我试图使用switchMap取消Angular2中以前的任何http调用。代码基本上是

var run = ():Observable<any> => {
        var url = 'http://...'
        return this._http.get(url)
            .map(result => {
                return var xmlData:string = result.text()

            });
    }


    function pollTasks() {
        return Observable.of(1)
            .switchMap(() => run())
            .map(res => res)
    }

    // caller can do subscription and store it as a handle:
    let tasksSubscription =
        pollTasks()
            .subscribe(data => {
                console.log('aa'+data)
            });

所以我连续几次打电话给整个来源并收到几个回复(即:aa + data)

我的印象是switchMap应该取消以前的调用。

typescript angular rxjs
4个回答
21
投票

请求需要源自相同的基础流。这是一个工厂函数,它将创建一个应该做你想做的http服务实例:

function httpService(url) {
   // httpRequest$ stream that allows us to push new requests
   const httpRequest$ = new Rx.Subject();

   // httpResponse$ stream that allows clients of the httpService
   // to handle our responses (fetch here can be replaced with whatever
   // http library you're using).
   const httpResponse$ = httpRequest$
       .switchMap(() => fetch(url));


   // Expose a single method get() that pushes a new
   // request onto the httpRequest stream. Expose the
   // httpResponse$ stream to handle responses.
   return {
       get: () => httpRequest$.next(),
       httpResponse$
   };
}

现在客户端代码可以使用这样的服务:

const http = httpService('http://my.api.com/resource');

// Subscribe to any responses
http.httpResponse$.subscribe(resp => console.log(resp));

// Call http.get() a bunch of times: should only get one log!!
http.get();
http.get();
http.get();

7
投票
constructor(private _http:Http, private appStore:AppStore) {

        this.httpRequest$ = new Subject();


        this.httpRequest$
            .map(v=> {
                return v;
        })
        .switchMap((v:any):any => {
            console.log(v);
            if (v.id==-1||v.id=='-1')
                return 'bye, cancel all pending network calls';                
            return this._http.get('example.com)
                .map(result => {
                    var xmlData:string = result.text()
                });
        }).share()
        .subscribe(e => {                
        })
    ...

并推送数据:

this.httpRequest$.next({id: busId});        

这很好用,我现在可以有一个服务,我可以管理所有网络电话,以及取消之前的电话...

看到下面的图片,当新的电话进来时,先前的电话被取消。请注意我如何设置慢速网络,延迟4秒,以提供所有正常工作...

enter image description here


3
投票

我认为当您使用switchMap运算符时,您只能取消当前数据流中的请求。我的意思是在同一个可观察链上发生的事件......

如果多次调用pollTasks方法,则无法取消先前的请求,因为它们不在同一数据流中......每次调用方法时都会创建一个可观察链。

我不知道你是如何触发执行请求的。

如果你想每500毫秒执行一次请求,你可以试试这个:

pollTasks() {
  return Observable.interval(500)
                .switchMap(() => run())
                .map(res => res.json());
}

在这种情况下,如果在500ms之后有进行中的请求,它们将被取消以执行新的请求

通过这种方法,您只需要调用一次pollTasks方法。

您还可以根据用户事件触发异步处理链。例如,在输入中填充字符时:

var control = new Control();
// The control is attached to an input using the ngFormControl directive
control.valueChanges.switchMap(() => run())
                .map(res => res.json())
                .subscribe(...);

有人建议在DOM事件上链接/启动更容易的处理链(fromEvent

看到这个链接:


0
投票

您可以使用Subject,但如果您这样做,则必须管理订阅和发布。如果你只想要一个返回Observable的方法来取消一个时间间隔内的请求,我会这样做:

observer: Observer<CustomObject>;
debug = 0;

myFunction(someValue) {
    this.observable = new Observable<CustomObject>(observer => {
        if (!this.observer) {
            this.observer = observer;
        }

       // we simulate http response time
        setTimeout(() => {
            this.observer.next(someValue);
            this.debug++;
        }, 1000);
    })
    .debounceTime(3000) // We cancel request withing 3s interval and take only the last one
    .switchMap(fn)
    .do(() => {
        console.log("debug", this.debug);
    });
}

一直使用相同的观察者让我们根据我们想要的任何方式取消请求(debounceTime,distinctUntilChanged,...)。

© www.soinside.com 2019 - 2024. All rights reserved.