Nodejs中关于socket.emit()的用法

Nodejs中关于socket.emit()的用法

我在《nodejs入门经典》看到一段代码 ##//HTML

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Socket.io Express Example</title>
  </head>
  <body>
    <h1>Socket.io Express Example</h1>
    <form id="set-nickname">
      <label for="nickname">Nickname:</label>
      <input type="text" id="nickname" />
      <input type="submit" />
    </form>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
    <script src="/socket.io/socket.io.js"></script>
    <script>
      var socket = io.connect();
      jQuery(function ($) { 
        var nickName = $('#nickname');
        var setNicknameForm = $('#set-nickname');
        setNicknameForm.submit(function(event) {
          event.preventDefault(); 
          socket.emit('nickname', nickName.val(), function (data) {
            if (data) {
              console.log('Nickname set successfully');
              setNicknameForm.hide();
            } else {
              setNicknameForm.prepend('<p>Sorry - that nickname is already taken.');
            }
          });
        });
      });
    </script>
  </body>
</html>

##//app.js

var app = require('express').createServer(),
    io = require('socket.io').listen(app),
    nicknames = [];

app.listen(3000);

app.get('/', function (req, res) {
  res.sendfile(__dirname + '/index.html');
});

io.sockets.on('connection', function (socket) {
  socket.on('nickname', function (data, callback) {
    if (nicknames.indexOf(data) != -1) { 
      callback(false);
    } else {
      callback(true);
      nicknames.push(data);
      socket.nickname = data;
      console.log('Nicknames are ' + nicknames);
    }
  });
  socket.on('disconnect', function () {
    if (!socket.nickname) return;
    if (nicknames.indexOf(socket.nickname) > -1) {
      nicknames.splice(nicknames.indexOf(socket.nickname), 1);
    }
    console.log('Nicknames are ' + nicknames);
  });
});

###在HTML中

socket.emit('nickname', nickName.val(), function (data) {
            if (data) {
              console.log('Nickname set successfully');
              setNicknameForm.hide();
            } else {
              setNicknameForm.prepend('<p>Sorry - that nickname is already taken.');
            }

第三个参数是不是向服务器传了一个参数?

###在app.js中

socket.on('nickname', function (data, callback) {
    if (nicknames.indexOf(data) != -1) { 
      callback(false);
    } else {
      callback(true);
      nicknames.push(data);
      socket.nickname = data;
      console.log('Nicknames are ' + nicknames);
    }

给传进的函数给上参数,但是这个函数不是应该在服务器端执行的么? 为什么用的是DOM的方法,在客户端执行了呢? 这个callback是怎么回事?


5 回复

在Node.js中使用socket.emit()方法可以将事件和数据发送到特定的WebSocket连接。下面是对你的问题的详细解释以及示例代码。

socket.emit()的基本用法

socket.emit()方法用于从客户端向服务器发送事件和数据。它接受两个或更多参数:

  • 第一个参数是事件名称。
  • 第二个参数(可选)是发送的数据。
  • 第三个参数(可选)是一个回调函数,用于接收来自服务器的响应。

示例代码

HTML部分

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Socket.io Example</title>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
  <script src="/socket.io/socket.io.js"></script>
</head>
<body>
  <h1>Socket.io Example</h1>
  <form id="set-nickname">
    <label for="nickname">Nickname:</label>
    <input type="text" id="nickname" />
    <input type="submit" value="Submit" />
  </form>
  <script>
    var socket = io.connect();

    jQuery(function($) {
      var nickName = $('#nickname');
      var setNicknameForm = $('#set-nickname');

      setNicknameForm.submit(function(event) {
        event.preventDefault();
        socket.emit('nickname', nickName.val(), function(data) {
          if (data) {
            console.log('Nickname set successfully');
            setNicknameForm.hide();
          } else {
            setNicknameForm.prepend('<p>Sorry - that nickname is already taken.</p>');
          }
        });
      });
    });
  </script>
</body>
</html>

Node.js服务器部分 (app.js)

const express = require('express');
const http = require('http');
const socketIo = require('socket.io');

const app = express();
const server = http.createServer(app);
const io = socketIo(server);

let nicknames = [];

app.get('/', (req, res) => {
  res.sendFile(__dirname + '/index.html');
});

io.on('connection', (socket) => {
  socket.on('nickname', (data, callback) => {
    if (nicknames.includes(data)) {
      callback(false); // 针对客户端的回调
    } else {
      callback(true); // 针对客户端的回调
      nicknames.push(data);
      socket.nickname = data;
      console.log('Nicknames are:', nicknames);
    }
  });

  socket.on('disconnect', () => {
    if (!socket.nickname) return;
    if (nicknames.includes(socket.nickname)) {
      nicknames.splice(nicknames.indexOf(socket.nickname), 1);
    }
    console.log('Nicknames are:', nicknames);
  });
});

server.listen(3000, () => {
  console.log('Server is running on port 3000');
});

解释

  1. 客户端发送事件

    socket.emit('nickname', nickName.val(), function(data) {
      if (data) {
        console.log('Nickname set successfully');
        setNicknameForm.hide();
      } else {
        setNicknameForm.prepend('<p>Sorry - that nickname is already taken.</p>');
      }
    });
    

    这里,socket.emit('nickname', nickName.val()) 发送一个名为'nickname'的事件,并附带输入框中的值作为数据。回调函数会在接收到服务器响应后执行。

  2. 服务器处理事件

    socket.on('nickname', (data, callback) => {
      if (nicknames.includes(data)) {
        callback(false);
      } else {
        callback(true);
        nicknames.push(data);
        socket.nickname = data;
        console.log('Nicknames are:', nicknames);
      }
    });
    

    服务器监听名为'nickname'的事件。当接收到事件时,检查昵称是否已存在。如果不存在,则添加到nicknames数组中,并通过callback(true)通知客户端。如果存在,则通过callback(false)通知客户端。

  3. 回调函数: 回调函数在客户端执行,用于处理服务器的响应。它可以在客户端的脚本中定义并立即传递给socket.emit()

通过这种方式,你可以实现客户端与服务器之间的双向通信,其中客户端可以发送请求并接收响应,而服务器可以处理这些请求并返回结果。


app.js中的callback(true)对应的就是html中的function (data),你可以把app.js中的callback(true)改为callback({name: ‘xiaoshan’}); html的function (data)中打印data.name,输出的就是xiaoshan

那为什么不把name这个参数传回去,而要在服务器调用这个函数呢?

  socket.on('nickname', function (data, callback) {
    if (nicknames.indexOf(data) != -1) { 
      callback(false);
    } else {
      callback(true);
      nicknames.push(data);
      socket.nickname = data;
      console.log('Nicknames are ' + nicknames);
    }
  });

是上边的代码在起作用, 看了半天才找到原来官网上有给例子的

Sending and getting data (acknowledgements). – http://socket.io/#how-to-use

socket.emit() 方法用于从客户端向服务器发送事件。在你提供的例子中,socket.emit('nickname', nickName.val(), function (data) { ... }) 发送了一个名为 'nickname' 的事件,并将 nickName.val() 作为数据传递给服务器。同时,它还接收一个回调函数,该回调函数在接收到服务器响应时执行。

客户端代码解析

在客户端(HTML 文件中的 JavaScript 代码):

socket.emit('nickname', nickName.val(), function (data) {
  if (data) {
    console.log('Nickname set successfully');
    setNicknameForm.hide();
  } else {
    setNicknameForm.prepend('<p>Sorry - that nickname is already taken.</p>');
  }
});

这里,nickName.val() 是要传递的数据,而回调函数会在服务器处理完请求后执行。如果服务器返回 true,则表示昵称设置成功;否则表示昵称已存在。

服务器端代码解析

在服务器端 (app.js):

io.sockets.on('connection', function (socket) {
  socket.on('nickname', function (data, callback) {
    if (nicknames.indexOf(data) != -1) {
      callback(false); // 返回 false,表示昵称已存在
    } else {
      callback(true); // 返回 true,表示昵称可用
      nicknames.push(data);
      socket.nickname = data;
      console.log('Nicknames are ' + nicknames);
    }
  });
  // 其他逻辑...
});

服务器端接收到 'nickname' 事件后,检查 nicknames 数组中是否已存在该昵称。如果存在,则调用 callback(false) 返回错误信息;如果不存在,则添加到 nicknames 数组并调用 callback(true) 返回成功信息。

总结

  • socket.emit() 用于发送事件和数据。
  • 回调函数在服务器响应后在客户端执行。
  • callback 是一种机制,用于在异步操作完成后通知客户端或服务器结果。

这种设计使得客户端和服务器之间可以进行双向通信,从而实现更复杂的功能。

回到顶部