简体   繁体   English

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

[英]Angular2: switchMap not canceling previous http calls

I am trying to use switchMap to cancel any previous http calls in Angular2. 我试图使用switchMap取消Angular2中以前的任何http调用。 The code is basically 代码基本上是

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

and so I call the entire source several times in a row and receive several replies (ie: aa+data) 所以我连续几次调用整个源并收到几个回复(即:aa + data)

I was under the impression switchMap should cancel the previous calls. 我的印象是switchMap应该取消以前的调用。

The requests need to originate from the same underlying stream. 请求需要源自相同的基础流。 Here's a factory function that will create an http service instance that should do what you want: 这是一个工厂函数,它将创建一个应该做你想做的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$
   };
}

And now the client code can use this service like this: 现在客户端代码可以使用这样的服务:

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();
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 => {                
        })
    ...

and to push data in: 并推送数据:

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

this works great and I can now have a single service that I can pipe all network calls through as well as cancel prior calls... 这很好用,我现在可以有一个服务,我可以管理所有网络电话,以及取消之前的电话...

see image below, as new calls come in, prior ones are canceled. 看到下面的图片,当新的电话进来时,先前的电话被取消。 note how I set slow network with a delay of 4sec to provide all is working as expected... 请注意我如何设置慢速网络,延迟4秒,以提供所有正常工作...

在此输入图像描述

I think when you use the switchMap operator, you can only cancel requests in the current data flow. 我认为当你使用switchMap运算符时,你只能取消当前数据流中的请求。 I mean the events that occur on the same observable chain... 我的意思是在同一个可观察链上发生的事件......

If you call your pollTasks method several times, you won't be able to the cancel previous requests because they won't be in the same data flow... You create an observable chain each time you call the method. 如果多次调用pollTasks方法,则无法取消先前的请求,因为它们不在同一数据流中......每次调用方法时都会创建一个可观察链。

I don't know how you trigger the execution of your requests. 我不知道你是如何触发执行请求的。

If you want to execute your request each 500ms, you could try this: 如果你想每500毫秒执行一次请求,你可以试试这个:

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

In this case, if there are in-progress request after 500ms, they will be canceled to execute the new one 在这种情况下,如果在500ms之后有进行中的请求,它们将被取消以执行新的请求

With the approach, you just need to call once the pollTasks method. 使用该方法,您只需要调用pollTasks方法一次。

You can also trigger the asynchronous processing chain based on user events. 您还可以根据用户事件触发异步处理链。 For example, when characters are filled in inputs: 例如,在输入中填充字符时:

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

There is a proposal to link / initiate more easily processing chain on DOM events ( fromEvent ) 有人建议在DOM事件上链接/启动更容易的处理链( fromEvent

See this link: 看到这个链接:

You can use Subject but if you do so, you have to manage subscription and publish. 您可以使用Subject,但如果您这样做,则必须管理订阅和发布。 If you just want a method returning Observable which cancel requests within a interval, here is how I would do that : 如果你只想要一个返回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);
    });
}

Using the same observer all along let us cancel requests according all we want (debounceTime, distinctUntilChanged, ...). 一直使用相同的观察者让我们根据我们想要的任何方式取消请求(debounceTime,distinctUntilChanged,...)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM