2
\$\begingroup\$

I wrote this to make the "callback hell" more manageable on the part of the coder when using Socket IO, so that there wasn't really any callback hell to go with, just a simple await.

This should work with any socket implementation, so long as it has socket.on, socket.emit, and socket.removeListener.

function emit_and_wait(socket, emit, data, wait_key, max_wait = 1000, error_on_timeout = true) {
    return new Promise(function(resolve, reject) {
        let responded = false,
             callback,
             removed = false;
        if(!socket) {
            reject("Socket supplied is not valid.")
        } else if(socket.disconnected) {
            reject("Socket is disconnected");
        }
        let timeout = setTimeout(function() {
            if(!responded) {
                if(error_on_timeout) {
                    reject("Socket timeout");
                } else {
                    resolve(null);
                }
                responded = true;
                if(!removed) {
                    socket.removeListener(wait_key, callback);
                    removed = true;
                }
            }
        }, max_wait)
        callback = function(data) {
            if(!removed) {
                socket.removeListener(wait_key, callback);
            }
            if(!responded) {
                resolve(data);
                clearTimeout(timeout);
            }
        }
        socket.on(wait_key, callback);
        socket.emit(emit, data)
    })
}
\$\endgroup\$
2
\$\begingroup\$

You have a few flags (removed, responded) which are almost equivalent and possibly useless. removeListener() won't cause any error if listener has been already removed then removed is unnecessary. After you called removeListener() your callback won't be called then also responded (which BTW is a misleading name) is unnecessary. Also, setTimeout() won't call its callback twice then again responded isn't necessary.

Use const instead of let whenever possible and declare your variables (usually one per line) when you initialize them. In (untested) code:

if (!socket) {
    reject("Socket supplied is not valid.");
    return;
}

if (socket.disconnected) {
    reject("Socket is disconnected");
    return;
}

const timeout = setTimeout(() => {
   socket.removeListener(wait_key, callback);

   if (error_on_timeout) {
       reject("Socket timeout");
   } else {
       resolve(null);
   }
}, max_wait)

const callback = (data) => {
    clearTimeout(timeout);
    socket.removeListener(wait_key, callback);
    resolve(data);
};

socket.on(wait_key, callback);
socket.emit(emit, data)

Few more notes: resolve() and reject() won't stop execution then you need to add the proper return. Use semicolon consistently: someone prefers to avoid semicolon as much as possible, pick a style and use it consistently.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.