Rxjs 如果发生其他事件,则取消展开

Rxjs 如果发生其他事件,则取消展开,rxjs,reactivex,Rxjs,Reactivex,我是ReactiveX新手,一直在尝试使用RxJS构建一个“CS:Go炸弹爆炸通知程序” 到目前为止,我有以下几点: //TimeSubject是游戏的当前心跳(即当前客户端时间), //不是每1秒发射一次(至少每30秒发射一次 //秒,以及任何其他游戏事件发生时) //RoundSubject存储有关当前和上一轮状态的信息 组合相关测试([TimeSubject,RoundSubject]) .烟斗( //探测炸弹何时被安放 过滤器(([[uu,{current}])=>current.bom

我是ReactiveX新手,一直在尝试使用RxJS构建一个“CS:Go炸弹爆炸通知程序”

到目前为止,我有以下几点:

//TimeSubject是游戏的当前心跳(即当前客户端时间),
//不是每1秒发射一次(至少每30秒发射一次
//秒,以及任何其他游戏事件发生时)
//RoundSubject存储有关当前和上一轮状态的信息
组合相关测试([TimeSubject,RoundSubject])
.烟斗(
//探测炸弹何时被安放
过滤器(([[uu,{current}])=>current.bomb==='planted'),
//创建一个计时器对象以跟踪爆炸前的时间
map(([time,)])=>({plantTime:time,explosionTime:time+40,currentTime:time}),
//在接下来的50秒内忽略其他“炸弹植入”事件
节流时间(50*1000),
//倒计时直到炸弹爆炸
//问题:RoundSubject可能会发出一个事件,指示炸弹被拆除
//或者在炸弹爆炸前子弹就结束了,
//但是,既然我正在限制来自该频道的事件,我该如何捕捉它呢?
展开({plantTime,explosionTime,currentTime})=>
爆炸时间>当前时间
?of({plantTime,explosionTime,currentTime:currentTime+1}))
.管道(延迟(1000))
:空)
).subscribe({plantTime,explosionTime,currentTime})=>{
如果(plantTime==当前时间)
console.log('炸弹被放置,40秒后爆炸!');
否则如果(爆炸时间>=当前时间){
const secondsToExplode=爆炸时间-当前时间;
log(`..explodes in:${secondstoexplodes}seconds`);
}
});
这里的问题是
RoundSubject
可能会发出类似
RoundEnded
Defused
的事件,这两种情况下都应该取消计时器

目前,我对可用的运营商了解不够,无法了解如何以良好的方式解决此问题。另外,我觉得我的代码和扩展代码非常复杂,所以如果您知道更好的方法,请告诉我:-)

谢谢。

首先:找到解决方案 下面是您可能会做的快速模拟:

/**********
*自定义操作员仅调节比排放量
*********/
函数优先级节流时间(
时间:号码,
priorityStr=“优先级”
):单类型运算符函数{
返回s=>defer(()=>{
const priorityTimeStamp=新映射();
回流管(
过滤器(v=>Date.now()(
priorityTimeStamp.get(v[priorityStr])||
0)>=thrTime
),
轻触(v=>{
如果(v[priorityStr]!=null){
priorityTimeStamp.set(
v[priorityStr],
日期:现在()
)
}
})
);
});
}
//TimeSubject是游戏的当前心跳(即当前客户端时间)
//RoundSubject存储有关当前和上一轮状态的信息
圆管(
//探测炸弹何时被放置,映射到优先级:1,
//否则,无需优先映射
地图(圆形=>
round.current.bomb===‘种植’?
({优先级:1,有效负载:round}):
({payload:round})
),
//相同优先事件(“炸弹植入”事件)
//在接下来的50秒内被忽略
优先节流时间(50*1000),
//节流完毕,把有效载荷拿回来
map({payload})=>payload),
//根据回合所做的事情创建一个新的可观察对象
开关映射({current})=>
current.bomb!==“种植”?
空的:
timeSubject.pipe(
//抓住下一个心跳
以(1)为例,
//创建一个计时器对象以跟踪爆炸前的时间
映射(时间=>({
时间:时间,
爆炸时间:时间+40,
当前时间:时间
})),
//倒计时直到炸弹爆炸
展开({plantTime,explosionTime,currentTime})=>
当前时间>爆炸时间?
空的:
({
plantTime,
爆炸时间,
currentTime:currentTime+1
})).管道(延迟(1000))
)
)
)
).subscribe({plantTime,explosionTime,currentTime})=>{
如果(plantTime==当前时间)
console.log('炸弹被放置,40秒后爆炸!');
否则如果(爆炸时间>=当前时间){
const secondsToExplode=爆炸时间-当前时间;
log(`..explodes in:${secondstoexplodes}seconds`);
}
});
一些解释 “我想根据某个上游事件取消正在进行的观测”模式应始终指向
switchMap

在上面的代码片段中,任何未被阻止的事件都将启动一个新炸弹,或者什么也不做。无论哪种方式,switchMap都将取消任何正在进行的炸弹(如果有)

你可能会看到,有相当大的空间来改变这种行为,但我不确定你想要什么,所以我把这留给你

优先节流时间 priorityThrottleTime对于你所需要的东西来说真是太过分了,但我很久以前就写过了,没有时间简化它。您可以重新编写它以获取谓词,并且仅当谓词返回true时才进行节流。这样,您就避免了映射到上面看到的
({priority,payload})
对象的麻烦

扩大 Expand是一个非常臃肿的计时器工具。这不是一个真正的问题,但我可以通过计算您已经维护的
timeSubject
的40秒来简化它

这样,您就不需要检查每个迭代

timeSubject.pipe(
//第一次排放是时间0,
//然后花40秒,然后停下来
以(41)为例,
//创建计时器对象
映射((当前时间,通过的时间)=>({
plantTime:currentTime-已通过的时间,
爆炸时间:40-时间流逝,
当前时间
}))
)
Th