监听事件

有几种方法可以处理在服务器和客户端之间传输的事件。

EventEmitter 方法

在服务器端,Socket 实例扩展了 Node.js EventEmitter类。

在客户端,Socket 实例使用component-emitter库提供的​​事件发射器,它公开了 EventEmitter 方法的子集。

socket.on(eventName, listener)

侦听器函数添加到名为eventName的事件的侦听器数组的末尾。

  1. socket.on("details", (...args) => {
  2. // ...
  3. });

socket.once(eventName, listener)

为名为eventName的事件添加一次性监听函数

  1. socket.once("details", (...args) => {
  2. // ...
  3. });

socket.off(eventName, listener)

从名为eventName的事件的侦听器数组中移除指定的侦听器

  1. const listener = (...args) => {
  2. console.log(args);
  3. }
  4. socket.on("details", listener);
  5. // and then later...
  6. socket.off("details", listener);

socket.removeAllListeners([eventName])

删除所有侦听器,或指定eventName的侦听器。

  1. // for a specific event
  2. socket.removeAllListeners("details");
  3. // for all events
  4. socket.removeAllListeners();

Catch-all 侦听器

从 Socket.IO v3 开始,受EventEmitter2库启发的新 API 允许声明 Catch-all 侦听器。

此功能在客户端和服务器上均可用。

socket.onAny(listener)

添加一个监听器,当任何事件发出时将被触发。

  1. socket.onAny((eventName, ...args) => {
  2. // ...
  3. });

socket.prependAny(listener)

添加一个监听器,当任何事件发出时将被触发。侦听器被添加到侦听器数组的开头。

  1. socket.prependAny((eventName, ...args) => {
  2. // ...
  3. });

socket.offAny([listener])

删除所有catch-all侦听器或给定的侦听器。

  1. const listener = (eventName, ...args) => {
  2. console.log(eventName, args);
  3. }
  4. socket.onAny(listener);
  5. // and then later...
  6. socket.offAny(listener);
  7. // or all listeners
  8. socket.offAny();

验证

事件参数的验证超出了 Socket.IO 库的范围。

JS 生态系统中有许多包涵盖了这个用例,其中包括:

带有joiacknowledgements的示例:

  1. const Joi = require("joi");
  2. const userSchema = Joi.object({
  3. username: Joi.string().max(30).required(),
  4. email: Joi.string().email().required()
  5. });
  6. io.on("connection", (socket) => {
  7. socket.on("create user", (payload, callback) => {
  8. if (typeof callback !== "function") {
  9. // not an acknowledgement
  10. return socket.disconnect();
  11. }
  12. const { error, value } = userSchema.validate(payload);
  13. if (error) {
  14. return callback({
  15. status: "KO",
  16. error
  17. });
  18. }
  19. // do something with the value, and then
  20. callback({
  21. status: "OK"
  22. });
  23. });
  24. });

错误处理

Socket.IO 库中目前没有内置的错误处理,这意味着您必须捕获任何可能在侦听器中引发的错误。

  1. io.on("connection", (socket) => {
  2. socket.on("list items", async (callback) => {
  3. try {
  4. const items = await findItems();
  5. callback({
  6. status: "OK",
  7. items
  8. });
  9. } catch (e) {
  10. callback({
  11. status: "NOK"
  12. });
  13. }
  14. });
  15. });

在服务器端,使用EventEmitter.captureRejections = true(实验性,请参见此处)也可能很有趣,具体取决于您的用例。

  1. require("events").captureRejections = true;
  2. io.on("connection", (socket) => {
  3. socket.on("list products", async () => {
  4. const products = await findProducts();
  5. socket.emit("products", products);
  6. });
  7. socket[Symbol.for('nodejs.rejection')] = (err) => {
  8. socket.emit("error", err);
  9. };
  10. });