0

I want to respond a JSON object to a path (e.g. /getAbsencesWithNames). I have used the includeNames() function to read data from a JSON file, process it and save it in a the global JSON object i am trying to respond. The problem is the following command res.end(JSON.stringify(temp, null, "\t")); executes asynchronously since there is I/O code within includeNames() function. How can i make this command wait for my function to complete, in other words make it run synchronously?

function includeNames(){
members().then(membersPayload => {
    // var counter = 1;
    for (var i in respondJson){
        var absencesID = respondJson[i].userId;
        for (var j in membersPayload){
            var membersID = membersPayload[j].userId;
            if (absencesID == membersID){
                var nameValue = membersPayload[j].name;
                JSON.stringify(nameValue);
                respondJson[i]["name"] = nameValue;
                // console.log(counter + ": " + membersPayload[j].name);
                // counter++;
                break;
            }
        }
    }
    console.log("ITERATION COMPLETED");
}).catch((err) => console.error('error: ' + error.message));
return respondJson;
};


app.get('/getAbsencesWithNames', async (req, res) => {
    var temp = await includeNames();
    res.end(JSON.stringify(temp, null, "\t"));
    console.log("RESPOND SENT");
});

Console output is:

RESPOND SENT
ITERATION COMPLETED

When i was expecting:

ITERATION COMPLETED
RESPOND SENT
  • 1
    `includeNames()` does not `return` anything. – Patrick Roberts Nov 05 '19 at 21:13
  • I don't understand, what does it mean? How can i make it return something? – Fotis Kolytoumpas Nov 05 '19 at 21:18
  • See [Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference](https://stackoverflow.com/q/23667086/1541563) It's the same question you have, but more generalized. – Patrick Roberts Nov 05 '19 at 21:38
  • 1
    You cannot synchronously return a value that is obtained asynchronously. Cannot be done. The non-blocking nature of Javascript's asynchronous functions means that your function returns BEFORE the asynchronous value is even available. See [the question yours was marked a duplicate of](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) for a full explanation of how you have to communicate back the result either by returning a promise or using a callback. Those are your choices. – jfriend00 Nov 05 '19 at 21:42
  • FYI, you should do `return members().then(...)` and put `return respondJson` inside the `.then()` handler. That will return a promise and your caller will use `await` or `.then()` on that promise to get the resolved value. – jfriend00 Nov 05 '19 at 21:44
  • Thank you for your answers. I apologize for duplicate, but i have been looking for so many hours for a solution on the internet without finding anything close to what i needed. Specifically, i could not find a real life example with Promises `.then();`. Everyone was using `setTimeout();` which not useful at all. The code below worked fine for me. – Fotis Kolytoumpas Nov 06 '19 at 10:03
  • `function includeNames(){ return new Promise((resolve) => { members().then(membersPayload => { for (var i in respondJson){ var absencesID = respondJson[i].userId; for (var j in membersPayload){ var membersID = membersPayload[j].userId; if (absencesID == membersID){ var nameValue = membersPayload[j].name; JSON.stringify(nameValue); respondJson[i]["name"] = nameValue; break; } } } console.log("ITERATION COMPLETED"); resolve(respondJson); }).catch((err) => console.error('error: ' + error.message)); }) };` – Fotis Kolytoumpas Nov 06 '19 at 10:05
  • `app.get('/getAbsencesWithNames', (req, res) => { includeNames().then((respondJson) => { res.end(JSON.stringify(respondJson, null, "\t")); console.log("RESPOND SENT"); }); });` – Fotis Kolytoumpas Nov 06 '19 at 10:05

1 Answers1

-1

You have to rewrite your function to return Promise.

function includeNames() {
  return new Promise((resolve, reject) => {
    members().then(membersPayload => {
        // var counter = 1;
        for (var i in respondJson){
            var absencesID = respondJson[i].userId;
            for (var j in membersPayload){
                var membersID = membersPayload[j].userId;
                if (absencesID == membersID){
                    var nameValue = membersPayload[j].name;
                    JSON.stringify(nameValue);
                    respondJson[i]["name"] = nameValue;
                    // console.log(counter + ": " + membersPayload[j].name);
                    // counter++;
                    break;
                }
            }
        }
        resolve(respondJson)
        console.log("ITERATION COMPLETED");
    })
  });
};

// you cant use it as you're using
const result = await includeNames()

// or with Promise chain
includeNames().then(result => console.log(result))
Rei
  • 37
  • 1
  • 3