Ad

Node.js Express API: How To Handle Multiple Callbacks

- 1 answer

I have an API endpoint, which executes a function, which in turn listens to some events via a web socket and then throws the response of it back via a callback to the api endpoint, so the endpoint can respond with this object to a http request.

Sometimes I get only one event, sometimes I get two events from the listener. When only the first event appears, I have no problems. Because the second event has priority, I am using setTimeout to wait for it, in case it still appears.

The problem ist, when the second event appears, my API endpoint responds with its object, but afterwards it crashes. I suppose it has something to do with the second callback and I don't know how to handle it. This is how the code is structured:

app.get('/api/myendpoint', function(req, res) {

    myVar_1 = req.query.myvar1;
    myVar_2 = req.query.myvar2;

    myFunction(myVar_1, myVar_2, function(data, error) {
        if (!error) res.json(data);
        else res.json({"error": String(error)});        
    });

});


function myFunction(myVar_1, myVar_2, callback){

    listenOnSocket.someEvent(myVar_1,
        function(error, event) {
            if (error) callback(null, error);
            else setTimeout(function() {callback(event, null);}, 6000);
        }
    );    

    listenOnSocket.someEvent(myVar_2,
        function(error, event) {
            if (!error) callback(event, null); 
            else callback(null, error);
        }
    );

};

This is what my errors look like:

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

Ad

Answer

Why its Happening?

  1. 1st event occurs at which you set a timeout for 6000 ms to call the callback function.
  2. 2nd event occurs before 6000 and the callback executes due to event 2. Response is sent here.
  3. timeout completes and the pending function passed to setTimeout executes the callback which would send the response again and its not possible to send headers to a response after its sent.

Solution

A basic solution would be to check a flag variable in the function passed to set timeout that whether the 2nd event has occured or not.

function myFunction(myVar_1, myVar_2, callback){

    let executed = false;
    listenOnSocket.someEvent(myVar_1,
        function(error, event) {
            if(!executed){
            executed = true
            if (error) callback(null, error);
            else setTimeout(function() {
                       callback(event, null);
                    }, 6000);
        }
       }
    );    

    listenOnSocket.someEvent(myVar_2,
        function(error, event) {
            if(!executed){
            executed = true;
            if (!error) callback(event, null); 
            else callback(null, error);
        }
       }
    );

};
Ad
source: stackoverflow.com
Ad