ポーリングにフォールバックするWebSocketを実装しようとしています。 WebSocket接続が成功した場合、readyState
は1になりますが、失敗した場合、readyState
は3になり、ポーリングを開始する必要があります。
私は次のようなものを試しました:
var socket = new WebSocket(url);
socket.onmessage = onmsg;
while (socket.readyState == 0)
{
}
if (socket.readyState != 1)
{
// fall back to polling
setInterval(poll, interval);
}
私は期待していました socket.readyState
非同期に更新し、すぐに読み取れるようにします。ただし、これを実行すると、ブラウザーがフリーズします(あきらめるまで約30分間開いたままにしました)。
おそらくonreadyStateChanged
イベントがあると思っていましたが、MDNリファレンスにはありませんでした。
これをどのように実装すればよいですか?どうやら空のループは機能せず、これに対するイベントはありません。
これはシンプルで完璧に機能します...最大時間に関する条件、またはより堅牢にするための試行回数を追加できます...
function sendMessage(msg){
// Wait until the state of the socket is not ready and send the message when it is...
waitForSocketConnection(ws, function(){
console.log("message sent!!!");
ws.send(msg);
});
}
// Make the function wait until the connection is made...
function waitForSocketConnection(socket, callback){
setTimeout(
function () {
if (socket.readyState === 1) {
console.log("Connection is made")
if (callback != null){
callback();
}
} else {
console.log("wait for connection...")
waitForSocketConnection(socket, callback);
}
}, 5); // wait 5 milisecond for the connection...
}
以下に、より詳細な説明を示します。すべてのブラウザーが最新のRFCに対応しているわけではないため、まず特定のブラウザーAPIを確認してください。あなたは相談することができます
常に実行状態をチェックするためにループを実行したくないので、余分なオーバーヘッドが必要です。より良い方法は、準備完了状態の変更に関連するすべてのイベントを理解し、それらを適切に結び付けることです。それらは次のとおりです。
onclose
WebSocket接続のreadyStateがCLOSEDに変更されたときに呼び出されるイベントリスナー。リスナーは、「close」という名前のCloseEventを受け取ります。
onerror
エラーが発生したときに呼び出されるイベントリスナー。これは、「エラー」という名前の単純なイベントです。
onmessage
サーバーからメッセージを受信したときに呼び出されるイベントリスナー。リスナーは、「message」という名前のMessageEventを受け取ります。
onopen
WebSocket接続のreadyStateがOPENに変更されたときに呼び出されるイベントリスナー。これは、接続がデータを送受信する準備ができていることを示します。イベントは、「open」という名前の単純なものです。
JSは完全にイベント駆動型であるため、これらすべてのイベントを接続し、readystateを確認するだけで、WSからポーリングに切り替えることができます。
Mozillaのリファレンスをご覧になることをお勧めします。RFC文書より読みやすく、APIの概要とその仕組みがわかります。 https://developer.mozilla.org/en- US/docs/WebSockets/WebSockets_reference/WebSocket
失敗した場合は、再試行のためのコールバックを行うことを忘れないでください。再接続が成功するためのコールバックが発生するまでポーリングしてください。
http://dev.w3.org/html5/websockets/ を見てください
「イベントハンドラ」を検索し、テーブルを見つけます。
onopen-> open
onmessage-> message
onerror-> error
onclose-> close
function update(e){ /*Do Something*/};
var ws = new WebSocket("ws://localhost:9999/");
ws.onmessage = update;
プーリングはまったく使用していません。代わりに、キューを使用します。まず、新しい送信関数とキューを作成します。
var msgs = []
function send (msg) {
if (ws.readyState !== 1) {
msgs.Push(msg)
} else {
ws.send(msg)
}
}
次に、接続が最初に確立されたときに読み取りと送信を行う必要があります。
function my_element_click () {
if (ws == null){
ws = new WebSocket(websocket_url)
ws.onopen = function () {
while (msgs.length > 0) {
ws.send(msgs.pop())
}
}
ws.onerror = function(error) {
// do sth on error
}
}
msg = {type: 'mymessage', data: my_element.value}
send(JSON.stringify(msg))
}
この例のWebSocket接続は、最初のクリックでのみ作成されます。通常、2回目のメッセージは直接送信され始めます。
私のユースケースでは、接続が失敗した場合に画面にエラーを表示したかった。
let $connectionError = document.getElementById("connection-error");
setTimeout( () => {
if (ws.readyState !== 1) {
$connectionError.classList.add( "show" );
}
}, 100 ); // ms
Safari(9.1.2)ではerror
イベントは発生しないことに注意してください-そうでなければ、これをエラーハンドラーに配置します。
Whileループがスレッドをロックしている可能性があります。使用してみてください:
setTimeout(function(){
if(socket.readyState === 0) {
//do nothing
} else if (socket.readyState !=1) {
//fallback
setInterval(poll, interval);
}
}, 50);