繁体   English   中英

如何取消订阅或处理Angular2或RxJS中可观察到的间隔?

[英]How to unsubscribe or dispose an interval observable on condition in Angular2 or RxJS?

我是整个Rx和响应式编程的新手,但是我必须处理这种情况。 我希望每隔500毫秒就可以观察到一个间隔,该间隔可以通过对REST API的POST请求来检查硬件的状态,以查看响应是否发生了变化。 因此,一旦更改,我希望立即关闭这种可观察间隔的POST请求,从而将资源留给以后的其他操作。 这是一段代码。

myLoop(item_array:number[], otheroption : string){
    for (let item of item_array){
        //set hardware option, still a request
        this.configHardware(item,otheroption)
        //after config the hardware, command hardware take action
            .flatMap(() => {
                //this return a session id for check status
                this.takeHardwareAction()
                    .flatMap( (result_id) => {
                        //I want every 500ms check if hardware action is done or not
                        let actionCheckSubscription = IntervalObservable.create(500).subscribe(
                            () => {
                                //So my question is, can I unsubscribe the actionCheckSubscription in here on condition change? For example, 
                                if (this.intervalCheckingStatus(result_id))
                                    actionCheckSubscription.unsubscribe() ;
                            }
                        ) ;
                    })

            })
    }
}

因此,您想每500毫秒发出一个POST请求,然后检查其响应。 我假设您的方法intervalCheckingStatus评估POST响应并确定它是否不同?

首先,我不会使用IntervalObservable。 您是否导入了RxJS模块? 这是Angular认可的第三方库,也是他们在所有开发人员指南样本中使用的库。 如果没有,请安装并导入。 https://github.com/Reactive-Extensions/RxJS

import * as Rx from 'rxjs/Rx';

我假设您已经导入了Http,ResponseOptions等,但是在此情况下,以防其他人感到好奇:

import { Http, Response, ResponseOptions } from '@angular/http';

编辑1:忘记包括依赖项注入。 将Http注入您的构造函数。 我已经将其称为http,因此如何称呼它。http.post

constructor(private http: Http) {

然后,我将执行以下操作:

编辑2:这将在您的循环内,其中post参数与您数组中的项目相关。

    // Every 500 ms, make a POST request
    Rx.Observable.interval(500)
                  // Add your POST arguments here
                 .map(_ => this.http.post(yourUrl, yourBody))
                 // This filter here is so that it will only emit when intervalCheckingStatus returns true
                 // You need to get the property you need from the Response: resp
                 // Is it the status code you're interested in? That's what I put as an example here but whatever it is, pass it to your method
                .filter(resp => this.intervalCheckingStatus(resp.status))
                // Take(1) takes only the first emitted value and once it does that, the observable completes. So you do NOT need to unsubscribe explicitly.
                .take(1);

如果您需要在响应具有所需状态(或任何属性)后执行某项操作,则将.sub链接到末尾并在其中执行所需的操作。 同样,由于take(1),一旦泵入第一个元素,可观察流就完成了,您无需取消订阅。

另外,这是一个非常有用的网站: http : //rxmarbles.com/#take您可以看到,在他们的示例中,采用2个元素后,所得的可观察对象是完整的(垂直线)。

您可以使用Observable.fromconcatMap遍历所有项,然后在验证通过filter filter后结合使用filtertake(1)停止间隔:

myLoop(item_array:number[], otheroption : string) {
    return Observable.from(item_array)
        .concatMap(item => this.configHardware(item, otheroption)
            .switchMap(resultId => Observable.interval(500)
                .switchMapTo(this.intervalCheckingStatus(resultId))
                .filter(status => Boolean(status)) // your logic if the status is valid, currently just a boolean-cast
                .take(1) // and complete after 1 value was valid
                .mapTo(item) // map back to "item" so we can notify the subscriber (this is optional I guess and depends on if you want this feature or not)
            )
        );
}

// usage:
myLoop([1,2,3,4], "fooBar")
    .subscribe(
        item => console.log(`Item ${item} is now valid`),
        error => console.error("Some error occured", error),
        () => console.log("All items are valid now")
    );

这是一个包含模拟数据的实时示例

 const Observable = Rx.Observable; function myLoop(item_array) { return Observable.from(item_array) // if you don't mind the execution-order you can use "mergeMap" instead of "concatMap" .concatMap(item => configHardwareMock(item) .switchMap(resultId => Observable.interval(500) .do(() => console.info("Checking status of: " + resultId)) .switchMap(() => intervalCheckingStatus(resultId)) .filter(status => Boolean(status)) // your logic if the status is valid, currently just a boolean-cast .take(1) // and complete after 1 value was valid .mapTo(item) // map back to "item" so we can notify the subscriber (this is optional I guess and depends on if you want this feature or not) ) ); } // usage: myLoop([1,2,3,4]) .subscribe( item => console.log(`Item ${item} is now valid`), error => console.error("Some error occured", error), () => console.log("All items are valid now") ); // mock helpers function configHardwareMock(id) { return Observable.of(id); } function intervalCheckingStatus(resultId) { if (Math.random() < .4) { return Observable.of(false); } return Observable.of(true); } 
 <script src="https://unpkg.com/rxjs/bundles/Rx.min.js"></script> 

暂无
暂无

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

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