イベントの発火
サーバーとクライアント間でイベントを送信するには、いくつかの方法があります。
TypeScriptユーザーの場合、イベントの型ヒントを提供することが可能です。こちらをご覧ください。
基本的なemit
Socket.IO APIは、Node.jsのEventEmitterから着想を得ています。つまり、片側でイベントを発行し、もう片側でリスナーを登録することができます。
サーバー
io.on("connection", (socket) => {
socket.emit("hello", "world");
});
クライアント
socket.on("hello", (arg) => {
console.log(arg); // world
});
これは逆方向にも動作します。
サーバー
io.on("connection", (socket) => {
socket.on("hello", (arg) => {
console.log(arg); // world
});
});
クライアント
socket.emit("hello", "world");
BufferやTypedArrayのようなバイナリオブジェクトを含む、任意の数の引数を送信でき、すべてのシリアライズ可能なデータ構造がサポートされています。
サーバー
io.on("connection", (socket) => {
socket.emit("hello", 1, "2", { 3: '4', 5: Buffer.from([6]) });
});
クライアント
// client-side
socket.on("hello", (arg1, arg2, arg3) => {
console.log(arg1); // 1
console.log(arg2); // "2"
console.log(arg3); // { 3: '4', 5: ArrayBuffer (1) [ 6 ] }
});
オブジェクトに対して`JSON.stringify()`を実行する必要はありません。自動的に実行されます。
// BAD
socket.emit("hello", JSON.stringify({ name: "John" }));
// GOOD
socket.emit("hello", { name: "John" });
注意事項
Dateオブジェクトは、文字列表現(例:`1970-01-01T00:00:00.000Z`)に変換されます(そして、文字列表現として受信されます)。
const serializedMap = [...myMap.entries()];
const serializedSet = [...mySet.keys()];
- オブジェクトのシリアライズをカスタマイズするには、`toJSON()`メソッドを使用できます。
クラスを使用した例
class Hero {
#hp;
constructor() {
this.#hp = 42;
}
toJSON() {
return { hp: this.#hp };
}
}
socket.emit("here's a hero", new Hero());
肯定応答
イベントは素晴らしいですが、場合によっては、より古典的なリクエスト-レスポンスAPIが必要になることがあります。Socket.IOでは、この機能は肯定応答と呼ばれています。
`emit()`の最後の引数としてコールバックを追加できます。このコールバックは、相手側がイベントを肯定応答すると呼び出されます。
サーバー
io.on("connection", (socket) => {
socket.on("update item", (arg1, arg2, callback) => {
console.log(arg1); // 1
console.log(arg2); // { name: "updated" }
callback({
status: "ok"
});
});
});
クライアント
socket.emit("update item", "1", { name: "updated" }, (response) => {
console.log(response.status); // ok
});
タイムアウト付き
Socket.IO v4.4.0以降、各emitにタイムアウトを割り当てることができるようになりました。
socket.timeout(5000).emit("my-event", (err) => {
if (err) {
// the other side did not acknowledge the event in the given delay
}
});
タイムアウトと肯定応答の両方を使用することもできます。
socket.timeout(5000).emit("my-event", (err, response) => {
if (err) {
// the other side did not acknowledge the event in the given delay
} else {
console.log(response);
}
});
揮発性イベント
揮発性イベントとは、基盤となる接続が準備されていない場合に送信されないイベントです(信頼性の点で、UDPのようなものです)。
これは、例えば、オンラインゲームでキャラクターの位置を送信する必要がある場合(最新の値のみが有用であるため)などに役立ちます。
socket.volatile.emit("hello", "might or might not be received");
もう1つのユースケースは、クライアントが接続されていないときにイベントを破棄することです(デフォルトでは、イベントは再接続されるまでバッファリングされます)。
例
サーバー
io.on("connection", (socket) => {
console.log("connect");
socket.on("ping", (count) => {
console.log(count);
});
});
クライアント
let count = 0;
setInterval(() => {
socket.volatile.emit("ping", ++count);
}, 1000);
サーバーを再起動すると、コンソールに次のように表示されます。
connect
1
2
3
4
# the server is restarted, the client automatically reconnects
connect
9
10
11
`volatile`フラグがない場合、次のように表示されます。
connect
1
2
3
4
# the server is restarted, the client automatically reconnects and sends its buffered events
connect
5
6
7
8
9
10
11