我正在尝试为接收命令的服务器实现自动重新连接客户端,然后使用单个字节进行回复。但是,问题是在处理命令时无法向服务器发送任何其他命令。所以我需要以某种方式序列化命令,是否可以在RxJS中以务实的方式实现?
const onClient = new BehaviourSubject(...) // Auto-reconnecting client
function sendCommand(cmd) {
return onClient
.concatMap(client => {
client.write(cmd + '\r\n')
return Rx.Observable.fromEvent(client, 'data').take(1)
})
}
sendCommand('CMD1').subscribe(x => console.log(x))
sendCommand('CMD2').subscribe(x => console.log(x)) // Oops, sent a command while another one is active...
这是一种可能的解决方案,缺乏错误处理,看起来效率很低。
const input = new Rx.Subject()
const output = new Rx.Subject()
input.concatMap(({cmd, id})) => onClient
.filter(client => client != null)
.concatMap(client => {
client.write(cmd + '\r\n')
return Rx.Observable.fromEvent(client, 'data').take(1)
})
.map(value => ({value, id}))
.subscribe(output)
function sendCommand(cmd) {
const id = cuid()
input.onNext(id)
return output
.filter(res => res.id === id)
.map(res => res.value)
}
有关改进的更好的想法或建议吗?
答案 0 :(得分:1)
这是我的直觉。我只使用过JavaRX,而这只是勉强。请注意,这假设您希望每次返回CMD1时都调用一次CMD2。
const onClient = new BehaviourSubject(...) // Auto-reconnecting client
function sendCommand(cmd) {
return onClient
.concatMap(client => {
client.write(cmd + '\r\n')
return Rx.Observable.fromEvent(client, 'data').take(1)
})
}
sendCommand('CMD1').subscribe(function(x) {
console.log(x);
sendCommand('CMD2').subscribe(y => console.log(y))
});
对于它的价值,你可能想考虑使用Promises来做这些事情。我对Rx的理解是它对于复杂的异步数据流很有用,比如事件流。但如果您想要的只是异步部分,我相信Promises可能会更容易。我们正在考虑在Java项目中使用它,并认为它不是我们需要的。请参阅:When to Use Rx
我不知道你在做什么,但是在我看来,命令响应模式可能会更好地服务于Promises,特别是如果你期望你传入的lambda {{1只能被调用一次。
答案 1 :(得分:0)
这是我最终得到的相当复杂的尝试:
import stampit from 'stampit'
import Rx from 'rx'
import cuid from 'cuid'
let input = new Rx.Subject()
let output = new Rx.Subject()
input
.concatMap(({fn, id}) => Rx.Observable
.defer(() => fn())
.map(value => ({value, id}))
.catch(error => Rx.Observable.return({error, id}))
.concat(Rx.Observable.return({id})))
.subscribe(output)
async function enqueue(fn) {
const id = cuid()
input.onNext({fn, id})
output
.filter(res => res.id === id)
.takeWhile(res => res.error || res.value)
.concatMap(res => res.error
? Rx.Observable.throw(res.error)
: Rx.Observable.return(res.value))
}
})
const onClient = new BehaviourSubject(...) // Auto-reconnecting client
function sendCommand(cmd) {
return enqueue(() => onClient
.concatMap(client => {
client.write(cmd + '\r\n')
return Rx.Observable.fromEvent(client, 'data').take(1)
}))
}
sendCommand('CMD1').subscribe(x => console.log(x))
sendCommand('CMD2').subscribe(x => console.log(x))