我是整个Rx事物和反应式编程的新手,但是我必须处理这种情况。我想要一个可观察的间隔来检查硬件的状态,每隔500ms通过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() ;
}
) ;
})
})
}
}
答案 0 :(得分:3)
因此,您希望每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,因此我如何调用this.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);
如果您需要在响应具有您正在寻找的状态(或任何属性)时执行某些操作,请将.subscribe链接到结尾并执行您需要的操作。同样,由于take(1),只要第一个元素被抽出,可观察流就完成了,你不需要取消订阅。
此外,这是一个非常有用的网站: http://rxmarbles.com/#take 您可以看到,在他们的示例中,在获取2个元素之后,生成的observable是完整的(垂直线)。
答案 1 :(得分:2)
您可以使用Observable.from
和concatMap
来遍历所有项目,然后使用filter
与take(1)
结合使用,以便在验证通过后立即停止间隔filter
:
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>