我使用rxjs来处理websocket连接
var socket = Rx.Observable.webSocket('wss://echo.websocket.org')
socket.resultSelector = (e) => e.data
我希望定期(5s)发送ping
消息并等待3秒以接收pong
响应并在未收到响应的情况下订阅该流。
我试着没有成功。我承认我有点失落,所有操作员都可以处理超时,延迟或限制。
// periodically send a ping message
const ping$ = Rx.Observable.interval(2000)
.timeInterval()
.do(() => socket.next('ping'))
const pong$ = socket
.filter(m => /^ping$/.test(`${m}`))
.mergeMap(
ping$.throttle(2000).map(() => Observable.throw('pong timeout'))
)
pong$.subscribe(
(msg) => console.log(`end ${msg}`),
(err) => console.log(`err ${err}`),
() => console.log(`complete`)
)
但不幸的是,没有发送ping。
我也试图在没有成功的情况下实现这一目标。
const ping$ = Rx.Observable.interval(2000)
.timeInterval()
.do(() => socket.next('ping'))
const pong$ = socket
.filter(m => /^ping$/.test(`${m}`))
const heartbeat$ = ping$
.debounceTime(5000)
.mergeMap(() => Rx.Observable.timer(5000).takeUntil(pong$))
heartbeat$.subscribe(
(msg) => console.log(`end ${msg}`),
(err) => console.log(`err ${err}`),
() => console.log(`complete`)
)
任何帮助表示赞赏。
答案 0 :(得分:1)
您可以使用race()
运算符始终只连接到首先发出的Observable:
function sendMockPing() {
// random 0 - 5s delay
return Observable.of('pong').delay(Math.random() * 10000 / 2);
}
Observable.timer(0, 5000)
.map(i => 'ping')
.concatMap(val => {
return Observable.race(
Observable.of('timeout').delay(3000),
sendMockPing()
);
})
//.filter(response => response === 'timeout') // remove all successful responses
.subscribe(val => console.log(val));
查看现场演示:https://jsbin.com/lavinah/6/edit?js,console
这随机模拟了0 - 5s
的回复。当响应时间超过{3}时,Observable.of('timeout').delay(3000)
首先完成,timeout
字符串由concatMap()
传递给其观察者。
答案 1 :(得分:0)
我终于找到了基于mergeMap
和takeUntil
我最初的错误是使用ping $作为我的heartBeat $的输入,我应该使用$ pong
// define the pong$
const pong$ = socket
.filter(m => /^ping$/.test(`${m}`))
.share()
//使用share()因为pong $被使用了两次
const heartbeat$ = pong$
.startWith('pong') // to bootstrap the stream
.debounceTime(5000) // wait for 5s after the last received pong$ value
.do(() => this.socket.next('ping')) // send a ping
.mergeMap(() => Observable.timer(3000).takeUntil(pong$))
// we merge the current stream with another one that will
// not produce value while a pong is received before the end of the
// timer
heartbeat$.subscribe(
(msg) => console.log(`handle pong timeout`),
)
答案 2 :(得分:0)
heartbeat $函数下面的函数返回一个可观察的声音,您可以连续收听
1)每5000毫秒的每次来回latency value
(socket.receive-socket.send时间)
或
2)-1
,如果往返行程超出阈值(例如3000ms)
即使发出了latency value
,您仍将继续收到-1
或-1
,这使您可以灵活地决定要做什么^。^
heartbeat$(pingInterval: number, pongTimeout: number) {
let start = 0;
const timer$ = timer(0, pingInterval).pipe(share());
const unsub = timer$.subscribe(() => {
start = Date.now();
this.ws.next('ping');
});
const ping$ = this.ws$.pipe(
switchMap(ws =>
ws.pipe(
filter(m => /^ping$/.test(`${m}`)),
map(() => Date.now() - start),
),
),
share(),
);
const dead$ = timer$.pipe(
switchMap(() =>
of(-1).pipe(
delay(pongTimeout),
takeUntil(ping$),
),
),
);
return merge(ping$, dead$).pipe(finalize(() => unsub.unsubscribe()));
}
heartbeat$(5000, 3000).subscribe(
(latency) => console.log(latency) // 82 83 82 -1 101 82 -1 -1 333 ...etc
)