【JS応用|実務向け】WebSocket.prototype.onclose を使いこなす:安定したリアルタイム通信のための切断処理術

導入:なぜ onclose が重要なのか

リアルタイム通信を行うアプリケーションにおいて、WebSocketの接続はネットワークの不安定さやサーバーの再起動など、様々な要因で切断されます。多くの開発者が「接続する処理」には注力しますが、「切断された後の処理」をおろそかにすると、ユーザー体験の低下やメモリリークを招きます。`WebSocket.prototype.onclose` を適切にハンドリングすることは、堅牢なフロントエンド実装における必須項目です。

基礎知識:onclose の仕組み

`onclose` は、WebSocket接続が閉じた時に呼び出されるイベントハンドラです。接続が正常に終了したのか、あるいはエラーによって強制終了されたのかを判別するための「CloseEvent」オブジェクトが引数として渡されます。
重要なプロパティは以下の2点です。
・wasClean: 接続が正常に閉じられた場合(closeフレームが交換された場合)に true となります。
・code: 終了コード(1000は正常終了、1006は異常終了など)を示します。

実装:堅牢な再接続ロジックの実装

単に切断を検知するだけでなく、自動再接続(Reconnection)を実装するのが実務での定石です。その際、指数バックオフ(間隔を徐々に広げる手法)を用いることで、サーバーへの負荷を軽減します。

サンプルプログラム

以下のコードは、切断時に自動再接続を試みるクラスベースの実装例です。

class ReconnectableWebSocket {
  constructor(url) {
    this.url = url;
    this.retryCount = 0;
    this.connect();
  }

  connect() {
    this.ws = new WebSocket(this.url);

    this.ws.onopen = () => {
      console.log('接続成功');
      this.retryCount = 0; // 接続成功時にリトライ回数をリセット
    };

    this.ws.onclose = (event) => {
      // wasCleanがfalseなら異常終了と判断
      if (!event.wasClean) {
        console.warn(`接続切断: コード ${event.code}。再接続を試みます...`);
        this.attemptReconnect();
      }
    };
  }

  attemptReconnect() {
    // 指数バックオフ: 1秒, 2秒, 4秒...と間隔を空ける(最大30秒)
    const delay = Math.min(Math.pow(2, this.retryCount)  1000, 30000);
    setTimeout(() => {
      this.retryCount++;
      this.connect();
    }, delay);
  }
}

// 利用例
const socket = new ReconnectableWebSocket('wss://example.com/socket');

応用・注意点:現場で陥りやすい罠

1. 無限ループの回避: サーバー側がメンテナンス中で常に接続を拒否している場合、クライアントが高速で再接続を繰り返すと「接続の嵐」を引き起こします。上記のサンプルにあるような「指数バックオフ」や「最大リトライ回数の制限」を必ず設けてください。
2. クリーンアップの徹底: コンポーネント(ReactのuseEffectなど)がアンマウントされる際は、`ws.onclose = null` とし、明示的に `ws.close()` を呼び出すことで、不要な再接続処理が走るのを防ぎましょう。
3. 状態管理の同期: フロントエンドのUI(例:「接続中」「切断中」の表示)は、`onclose` のイベントと同期させる必要があります。ReduxやZustandなどのストアを使用している場合、このイベント内で状態を更新するのを忘れないでください。

タイトルとURLをコピーしました