socket.io emit callback调用探秘

Posted lightsong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了socket.io emit callback调用探秘相关的知识,希望对你有一定的参考价值。

socket.io

https://socket.io/

https://socket.io/docs/

 

What Socket.IO is

Socket.IO is a library that enables real-time, bidirectional and event-based communication between the browser and the server. It consists of:

 

emit callback 用法

https://stackoverflow.com/questions/20337832/is-socket-io-emit-callback-appropriate

Recently I have been messing around with socket.io and found this interesting thing, that I can have emit function callback like this.

I start emitting on client side like this:

client.emit(‘eventToEmit‘, dataToEmit, function(error, message){
    console.log(error);
    console.log(message);
});

Then I can fire a callback from server-side like this:

client.on(‘eventToEmit‘, function(data, callback){
    console.log(data);
    callback(‘error‘, ‘message‘);
});

Everything works fine with no errors, but I am interested if doing something like this is appropriate since I have not seen anything similar in the documentation or any example so far.

见老外的疑惑,也是本篇的主题, 为什么服务器端能够直接调用客户端设置的回调函数。

跨进程可以调用函数,真是稀奇。 类似RPC。

 

官方文档的解释

https://socket.io/docs/#Sending-and-getting-data-acknowledgements

Sending and getting data (acknowledgements)

Sometimes, you might want to get a callback when the client confirmed the message reception.

To do this, simply pass a function as the last parameter of .send or .emit. What’s more, when you use .emit, the acknowledgement is done by you, which means you can also pass data along:

Server (app.js)

var io = require(‘socket.io‘)(80);

io.on(‘connection‘, function (socket) {
socket.on(‘ferret‘, function (name, word, fn) {
fn(name + ‘ says ‘ + word);
});
});

Client (index.html)

<script>
var socket = io(); // TIP: io() with no args does auto-discovery
socket.on(‘connect‘, function () { // TIP: you can avoid listening on `connect` and listen on events directly too!
socket.emit(‘ferret‘, ‘tobi‘, ‘woot‘, function (data) { // args are sent in order to acknowledgement function
console.log(data); // data will be ‘tobi says woot‘
});
});
</script>

 

 

代码跟踪

https://github.com/socketio/socket.io-client

以客户端源码为研究对象。

 

在socket.js文件中,存在emit实现:

如下代码中, 17-20行代码中, 会将callback函数存储到本地的acks数组中, 并将基数记为 packet.id,

然后packet作为数据整体,传送的服务器端。

 1 Socket.prototype.emit = function (ev) {
 2   if (events.hasOwnProperty(ev)) {
 3     emit.apply(this, arguments);
 4     return this;
 5   }
 6 
 7   var args = toArray(arguments);
 8   var packet = {
 9     type: (this.flags.binary !== undefined ? this.flags.binary : hasBin(args)) ? parser.BINARY_EVENT : parser.EVENT,
10     data: args
11   };
12 
13   packet.options = {};
14   packet.options.compress = !this.flags || false !== this.flags.compress;
15 
16   // event ack callback
17   if (‘function‘ === typeof args[args.length - 1]) {
18     debug(‘emitting packet with ack id %d‘, this.ids);
19     this.acks[this.ids] = args.pop();
20     packet.id = this.ids++;
21   }
22 
23   if (this.connected) {
24     this.packet(packet);
25   } else {
26     this.sendBuffer.push(packet);
27   }
28 
29   this.flags = {};
30 
31   return this;
32 };

 

服务器端处理完数据后, 调用callback接口后,服务器端调用的接口为包装接口, 包装了数据为packet, 并将id打在packet上, 表示此packet为emit时候的packet对应。

服务器端数据到来后, 根据packet.id定位到 callback函数, 并将packet.data作为参数传递到callback中。

/**
 * Called upon a server acknowlegement.
 *
 * @param {Object} packet
 * @api private
 */

Socket.prototype.onack = function (packet) {
  var ack = this.acks[packet.id];
  if (‘function‘ === typeof ack) {
    debug(‘calling ack %s with %j‘, packet.id, packet.data);
    ack.apply(this, packet.data);
    delete this.acks[packet.id];
  } else {
    debug(‘bad ack %s‘, packet.id);
  }
};

 

致此实现上彻底明了了。

 

以上是关于socket.io emit callback调用探秘的主要内容,如果未能解决你的问题,请参考以下文章

socket.io - socket.emit、socket.on、socket.send

io.sockets.socket(socket_id).emit() - 没有方法'socket'

socket.io的emit使用清单

socket.io 中的 emit 方法的成功回调

Socket.io Emit 不起作用

socket io 的 emit 函数是如何工作的?