2

I am trying to build a messaging web app using socket io and redux, and this post comes across. I can't comment on the post to ask questions, so I am posting a new question asking about the answer in that post(sorry if I violate stackoverflow quideline, but there seems to be no way for me to comment.) The part I don't understand is

In socketClient.js

 emit(event, data) {
    return new Promise((resolve, reject) => {
      if (!this.socket) return reject('No socket connection.');

      return this.socket.emit(event, data, (response) => {
        // Response is the optional callback that you can use with socket.io in every request. See 1 above.
        if (response.error) {
          console.error(response.error);
          return reject(response.error);
        }

        return resolve();
      });
    });
  }

I don't quite understand the callback funciton in this.socket.emit. From what I understand, the call back function will be executed on server side, when the server receive the event, data and callback funciton from client. If that's the case, what does the return do in the callback function? what should response be? and what should this.socket.emit return? and how can the server resolve a promise on client side?

I-PING Ou
  • 435
  • 4
  • 14

1 Answers1

12

I don't quite understand the callback function in this.socket.emit.

When you pass a callback as the third argument to socket.io's .emit() method, it tells socket.io that you want an acknowledgement that the server has received the message and an optional response back from the server. That callback will be called after the server has received your message and called a callback on its end and the server has the option of sending a response back with that.

The return statements inside that callback are only for flow of control. They just cause code to stop executing in the callback. People tend to forget that reject() and resolve() are just function calls. They don't cause the rest of the function to stop executing.

The code you show could have been written like this with only the one return statement to return the promise:

 emit(event, data) {
     return new Promise((resolve, reject) => {
         if (!this.socket) {
             reject('No socket connection.');
         } else {
             this.socket.emit(event, data, (response) => {
                 if (response.error) {
                     console.error(response.error);
                     reject(response.error);
                 } else {
                     resolve();
                 }
             });
         }
     });
 }

Here, it uses if/else to control program flow rather than using return to stop execution of the function early. Either can work - personal preference.

If that's the case, what does the return do in the callback function?

It just stops further code from executing inside the callback function. Just a control flow thing. There is no meaningful value to return from the callback.

what should response be?

response will be whatever the server sent as part of the acknowledgement.

what should this.socket.emit return?

this.socket.emit() happens to return the socket itself (allows for method chaining). But, that's not relevant here because there's no point in returning any value from a Promise executor function. If you do return a value, it is not used by the Promise in any way. Basically, there's too many return statements in that original code. They lead one to think the return value is relevant when it isn't. They do no harm, but do cloud up the proper intent and meaning of the code.

and how can the server resolve a promise on client side?

The server doesn't actually resolve a promise on the client side. The client defines a promise that will resolve when it gets a response back from the server. So, when that response comes back from the server, the client's own callback code that receives that response, then resolves its own promise.

What I don't get still is the callback function. So the client sends data and a callback function A to the server, and the server can call this function A in it's own callback. Function A will NOT be executed on client side, is this understanding correct? If so, then why is there resolve and reject in callback function A?

No. That's not what's happening. The client specifies a callback function to socket.io when it calls the .emit(). That tells the client socket.io library that the client would LIKE to get an acknowledgement for this message. That causes the socket.io library to set an extra bit in the message packet it sends to the server to TELL the server that the client wants an acknowledgement. No callback is sent to the server, only a request for acknowledgement bit. Then, when the server receives the message, it can call a server-side socket.io callback to say "yes, I acknowledge that I got this message" and it can also send a response. When the server calls that socket.io callback, socket.io will send an acknowledgement packet (with a matching message ID embedded in it) to the client. The socket.io client library will see the incoming acknowledgement packet, find the message ID in that packet and any server response data, find the client-side acknowledgement callback that goes with message ID and call it. The client will see its function getting called which tells it that the server did receive its message. Then, in your client code, that callback will resolve the promise.

jfriend00
  • 580,699
  • 78
  • 809
  • 825
  • "That callback will be called after the server has received your message" This sentence makes it sound a bit like the ack is part of what socket.io does. The ack callbacks are an explicit call made in client or server code to trigger the response. – Matt Dec 01 '17 at 05:28
  • @Matt - It's a feature offered in socket.io. I do think the server must call the callback on its end for the acknowledgement to happen. – jfriend00 Dec 01 '17 at 05:30
  • thank you for the detailed answer. I understand the return as flow control now. What I don't get still is the callback function. So the client sends data and a callback function A to the server, and the server can call this function A in it's own callback. Function A will NOT be executed on client side, is this understanding correct? If so, then why is there resolve and reject in callback function A? – I-PING Ou Dec 01 '17 at 07:04
  • And if the server does send a response to client, won't it need to another call socket.emit(...), but then it'll be another socket.on(...) from client side that gets the response, not this emit from the client side, right? Then how will this emit(from the cliet side) resolve the promise? Thank you so much! – I-PING Ou Dec 01 '17 at 07:06
  • @I-PINGOu - No. It sounds like you don't yet understand how the socket.io message acknowledgement works. I added an explanation of that to the end of my answer. – jfriend00 Dec 01 '17 at 07:13
  • Thank you so much!! That makes so much sense now. I was getting it all wrong. thank you~!! – I-PING Ou Dec 01 '17 at 07:52