0

I am using socket.io and I'd like to convert the callback function into a simple promise based function where I can return a value.

I'm trying to convert the acknowledgement found here: socket.io/docs/#sending-and-getting-data-(acknowledgements)

socket.on('getGames', (data, callback) => {
    Game.find(data)
        .then(data => callback(data)); //explicit call to callback
});

I'd like to call a function instead such as:

socketEvent(socket, 'getGames')
    .then((data) => {
        return Game.find(data); //returns a promise and can be chained
    });

I'm thinking something like:

//this doesn't work
const socketEvent = (socket, name) => {
    return new Promise(function (resolve, reject) {
        socket.on(name, (data, callback) => {
            resolve((data) => callback(data));
        });
    });
};
Nazzanuk
  • 61
  • 7
  • 2
    You probably shouldn't at all. A socket may fire the event multiple times, a promise is the wrong tool to represent that. – Bergi Feb 17 '17 at 15:47
  • Well in any case it would fire a callback multiple times. The context isn't that relevant - I'd still like to know how to convert an explicit callback as above into a promise. – Nazzanuk Feb 17 '17 at 15:50
  • 1
    A promise *cannot* fire multiple times, you're out of luck there. For the general case, see [How do I convert an existing callback API to promises?](http://stackoverflow.com/q/22519784/1048572) – Bergi Feb 17 '17 at 15:57
  • 2
    You seem to be a bit confused about socket.io callback functions. You can register a callback function when you SEND a message that will give you confirmation the message was received by the other end. You don't use that callback upon receipt of an incoming message. – jfriend00 Feb 17 '17 at 16:56
  • @jfriend00 thank you, this helped me understand my mistake. What I am referring to as a callback, is in fact a send function exposed as an argument. I would still like to 'promisify' the action, but I'll leave it for now. – Nazzanuk Feb 17 '17 at 17:26

2 Answers2

1

Just resolve(data). No need for an inner function. That will flow into the promise chain.

Also don't forget to call reject when there's a problem.

Daniel A. White
  • 187,200
  • 47
  • 362
  • 445
  • This doesn't work as I haven't then invoked `callback` to return `data`. I need to invoke `callback`, when the promise is resolved. – Nazzanuk Feb 17 '17 at 15:15
  • @Nazzanuk can you link to some documentation? – Daniel A. White Feb 17 '17 at 15:16
  • @Nazzanuk What data are you trying to send back? Where would it come from? – JLRishe Feb 17 '17 at 15:16
  • @DanielA.White So I'm trying to convert the acknowledgement found here: http://socket.io/docs/#sending-and-getting-data-(acknowledgements) – Nazzanuk Feb 17 '17 at 15:18
  • @JLRishe the information is just an example so in this case `Game.find(data)` is querying MongoDB with the `data` object. But any async Promise could be put in here. – Nazzanuk Feb 17 '17 at 15:44
1

Your second code snippet is not analogous to the first. In the first one, there is a mechanism to send an acknowledgement when Game.find() has retrieved its value, but in the second one, there's no way for it to send the acknowledgement back when its done.

I think this might be close to what you are trying to do:

const socketEvent = (socket, name) => {
    return new Promise(function (resolve, reject) {
        socket.on(name, (data, sendBack) => resolve({ data, sendBack }));
    });
};

You could then consume it like this:

socketEvent(socket, 'getGames')
    .then({ data, sendBack } => Game.find(data).then(sendBack))
    .then(... more stuff);

However, as others have pointed out, there is still a LARGE difference between this and the original code because the promise version will only capture the event once (that's how promises work). If you need to set up a mechanism to capture the same event multiple times, then promises are not the right tool for the job and you either need to use callbacks, or something like observables.

JLRishe
  • 99,490
  • 19
  • 131
  • 169