Skip to main content
Version: 4.x

触发事件

有多种方法可以在服务器和客户端之间发送事件。

¥There are several ways to send events between the server and the client.

tip

对于 TypeScript 用户,可以为事件提供类型提示。请检查 this

¥For TypeScript users, it is possible to provide type hints for the events. Please check this.

基本触发

¥Basic emit

Socket.IO API 的灵感来自 Node.js EventEmitter,这意味着你可以在一侧触发事件并在另一侧注册监听器:

¥The Socket.IO API is inspired from the Node.js EventEmitter, which means you can emit events on one side and register listeners on the other:

服务器

¥Server

io.on("connection", (socket) => {
socket.emit("hello", "world");
});

客户端

¥Client

socket.on("hello", (arg) => {
console.log(arg); // world
});

这也适用于另一个方向:

¥This also works in the other direction:

服务器

¥Server

io.on("connection", (socket) => {
socket.on("hello", (arg) => {
console.log(arg); // world
});
});

客户端

¥Client

socket.emit("hello", "world");

你可以发送任意数量的参数,并且支持所有可序列化的数据结构,包括 缓冲TypedArray 等二进制对象。

¥You can send any number of arguments, and all serializable data structures are supported, including binary objects like Buffer or TypedArray.

服务器

¥Server

io.on("connection", (socket) => {
socket.emit("hello", 1, "2", { 3: '4', 5: Buffer.from([6]) });
});

客户端

¥Client

// 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(),因为它将为你完成。

¥There is no need to run JSON.stringify() on objects as it will be done for you.

// BAD
socket.emit("hello", JSON.stringify({ name: "John" }));

// GOOD
socket.emit("hello", { name: "John" });

注意:

¥Notes:

  • 日期 对象将被转换为(并作为)其字符串表示形式接收,例如 1970-01-01T00:00:00.000Z

    ¥Date objects will be converted to (and received as) their string representation, e.g. 1970-01-01T00:00:00.000Z

  • 映射Set 必须手动序列化:

    ¥Map and Set must be manually serialized:

const serializedMap = [...myMap.entries()];
const serializedSet = [...mySet.keys()];
  • 你可以使用 toJSON() 方法来自定义对象的序列化

    ¥you can use the toJSON() method to customize the serialization of an object

类的示例:

¥Example with a class:

class Hero {
#hp;

constructor() {
this.#hp = 42;
}

toJSON() {
return { hp: this.#hp };
}
}

socket.emit("here's a hero", new Hero());

回执

¥Acknowledgements

事件很棒,但在某些情况下你可能需要更经典的请求-响应 API。在 Socket.IO 中,此功能称为确认。

¥Events are great, but in some cases you may want a more classic request-response API. In Socket.IO, this feature is named acknowledgements.

你可以添加一个回调作为 emit() 的最后一个参数,一旦对方确认该事件,就会调用该回调:

¥You can add a callback as the last argument of the emit(), and this callback will be called once the other side acknowledges the event:

服务器

¥Server

io.on("connection", (socket) => {
socket.on("update item", (arg1, arg2, callback) => {
console.log(arg1); // 1
console.log(arg2); // { name: "updated" }
callback({
status: "ok"
});
});
});

客户端

¥Client

socket.emit("update item", "1", { name: "updated" }, (response) => {
console.log(response.status); // ok
});

使用超时

¥With timeout

从 Socket.IO v4.4.0 开始,你现在可以为每个触发分配超时:

¥Starting with Socket.IO v4.4.0, you can now assign a timeout to each emit:

socket.timeout(5000).emit("my-event", (err) => {
if (err) {
// the other side did not acknowledge the event in the given delay
}
});

你还可以同时使用超时和 回执

¥You can also use both a timeout and an acknowledgement:

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);
}
});

不稳定事件

¥Volatile events

易失性事件是如果底层连接没有准备好就不会发送的事件(就可靠性而言有点像 UDP)。

¥Volatile events are events that will not be sent if the underlying connection is not ready (a bit like UDP, in terms of reliability).

例如,如果你需要发送在线游戏中角色的位置(因为只有最新值才有用),这可能会很有趣。

¥This can be interesting for example if you need to send the position of the characters in an online game (as only the latest values are useful).

socket.volatile.emit("hello", "might or might not be received");

另一个用例是在客户端未连接时丢弃事件(默认情况下,事件将被缓冲直到重新连接)。

¥Another use case is to discard events when the client is not connected (by default, the events are buffered until reconnection).

示例:

¥Example:

服务器

¥Server

io.on("connection", (socket) => {
console.log("connect");

socket.on("ping", (count) => {
console.log(count);
});
});

客户端

¥Client

let count = 0;
setInterval(() => {
socket.volatile.emit("ping", ++count);
}, 1000);

如果重新启动服务器,你将在控制台中看到:

¥If you restart the server, you will see in the console:

connect
1
2
3
4
# the server is restarted, the client automatically reconnects
connect
9
10
11

如果没有 volatile 标志,你会看到:

¥Without the volatile flag, you would see:

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