typescript Angular2:switchMap 没有取消之前的 http 调用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35765322/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 03:19:41  来源:igfitidea点击:

Angular2: switchMap not canceling previous http calls

typescriptangularrxjs

提问by born2net

I am trying to use switchMap to cancel any previous http calls in Angular2. The code is basically

我正在尝试使用 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)
            });

and so I call the entire source several times in a row and receive several replies (i.e.: aa+data)

所以我连续多次调用整个源并收到几个回复(即:aa+data)

I was under the impression switchMap should cancel the previous calls.

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

回答by Calvin Belden

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

回答by born2net

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 秒的慢速网络以提供所有按预期工作...

enter image description here

在此处输入图片说明

回答by Thierry Templier

I think when you use the switchMapoperator, you can only cancel requests in the current data flow. I mean the events that occur on the same observable chain...

我觉得你在使用switchMapoperator的时候,只能取消当前数据流中的请求。我的意思是发生在同一个可观察链上的事件......

If you call your pollTasksmethod 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

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

With the approach, you just need to call once the pollTasksmethod.

使用该方法,您只需要调用一次该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:

请参阅此链接:

回答by marvinroller

You can use Subject but if you do so, you have to manage subscription and publish. 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、...)。