1

I am trying to do two post requests in JavaScript (client-side), but the second one seems to run before the first one is completed.

This is the code I have:

Client-side code:

$.post("/startGame", {username: username});
$.post("/lookingForAPlayer", {});

Server-side code:

var idPlayer;
app.post('/startGame', function(req, res) {
    const idPlayerProm = new Promise((resolve, reject) => {
        dbConnection.getIdPlayer(req.body.username).then(data => {
            resolve(data)
        });
    });

    Promise.all([idPlayerProm]).then(data => {
        idPlayer = data[0];
        console.log("idPlayer1: " + idPlayer) //Here idPlayer has a value
        const gamePromise = new Promise((resolve, reject) => {
            dbConnection.addGame(idPlayer).then(data => {
                resolve(data);
            });
        });    
        Promise.all([gamePromise]).then(data => {
            idGame = data[0];
        });
    })   
});

app.post('/lookingForAPlayer', function(req, res) {
    console.log("idPlayer2: " + idPlayer); //Here idPlayer is undefined
});

Result:

enter image description here

As you can see, it even prints idPlayer2 at first when should be printed after idPlayer1.

I am guessing I need to do some sort of Promise in the client side, but I am not sure how as I am new at doing them on the client-side.

Any help?

Update for @DanMossa (I cannot get the value I send from the server with his/her answer).

app.post('/startGame', function(req, res) {
    dbConnection.getIdPlayer(req.body.username).then(data1 => {
        dbConnection.addGame(data1).then(data2 => {
            res.end(JSON.stringify([data1, data2]));
        });
    });
});

app.post('/lookingForAPlayer', function(req, res) {
    //Here I will also res.end() as I do in /startGame.
});
  • Even if your client was waiting for a response before sending the second request (see https://stackoverflow.com/q/14220321/3001761), note that global state in your backend is a terrible idea if you're expecting any more than one users. – jonrsharpe May 18 '20 at 19:41
  • Then what should I do? I need to save the id of the user who is logging in. (since I need it later) –  May 18 '20 at 19:43
  • Well, how *do* you know which of the users who has called `/startGame` is now calling `/lookingForAPlayer`? Maybe you should tell them what their user ID is, so they can use it in subsequent requests? Note also that using `Promise.all` with an array of one promises seems pointless. – jonrsharpe May 18 '20 at 19:47
  • Maybe you are right... I have not thought about that. In that case, maybe saving it to a variable in the client-side would be a better idea? I am using `Promise.all` because someone told me to do it so when I had issues in another app I was building and as it works, I thought it was fine to use it. I'll have to learn more about how Promises work... What should I use instead? –  May 18 '20 at 19:55
  • Just the one promise, and note that `new Promise`s are pointless too, given that you're creating a new promise to wrap what's *already a promise*: `dbConnection.getIdPlayer(...).then((idPlayer) => dbConnection.addGame(idPlayer)).then((idGame) => ...)`. In general, avoid [programming by coincidence](https://pragprog.com/the-pragmatic-programmer/extracts/coincidence). – jonrsharpe May 18 '20 at 19:58
  • Ok, I will look into it... I thought promises were needed because the server needs to wait for a response from the database. –  May 18 '20 at 20:07
  • Promises *are* needed, but the DB connection *already creates them*. That's why you can use .then on the result. So wrapping that in a second promise is pointless. – jonrsharpe May 18 '20 at 20:08
  • Ok, I see. It also works, but I hope it is alright: Let me know: https://i.imgur.com/GYDLaJ0.png. Also, I need to delete resolve and reject apparently. I do not use them. –  May 18 '20 at 20:21
  • 1
    If you don't use them, surely there's no point to `new Promise` at all? – jonrsharpe May 18 '20 at 20:22
  • Right, I have just deleted it. Works fine. Thanks! –  May 18 '20 at 20:25

2 Answers2

1

Working off of @Yousaf 's post, using async/await might make it easier to mentally visualize.

try {
  const res = await fetch('/startGame', {
    method: 'POST',
    body: JSON.stringify({ username: username }),
    headers: { 'Content-Type': 'application/json' },
  });

  await fetch('/lookingForAPlayer', {
    method: 'POST',
    body: JSON.stringify({}),
    headers: { 'Content-Type': 'application/json' },
  });
} catch (error) {
  console.log(error);
}
DanMossa
  • 994
  • 2
  • 17
  • 48
  • That does not work. It says `await is only valid in async function` –  May 18 '20 at 20:02
  • @Adrian2895 Yeah, that is true. Is this inside of a function at all? Or is it top level (not in a function)? – DanMossa May 18 '20 at 20:04
  • It is inside a method from a class. So: `class Game() { startGame() {//here }}` –  May 18 '20 at 20:06
  • Ah I see. In that case you could go ahead and make startGame() async by doing `async StartGame() {` – DanMossa May 18 '20 at 20:07
  • Nope, there is an error according to my IDE: https://i.imgur.com/6isa4pI.png. Keep in mind that I am doing this in the client-side. –  May 18 '20 at 20:10
  • 2
    @Adrian2895 async is misspelled – DanMossa May 18 '20 at 20:34
  • Ooops, right. Sorry, I did not notice about it. It works now. Thanks, I am accepting your answer as I prefer it being easier to mentally visualize. –  May 18 '20 at 21:09
  • Hey again. I am now testing this because I finally need it... How do I get the value I send from the server-side when I use `res.end()`? I have tried printing `res` but the object does not contain anything I send from the server: https://imgur.com/a/7szPPHR. I am going to update my main post so you can see my current server-side code. –  May 18 '20 at 21:52
  • I have tried to do it with `JQuery` as I always use this library for post requests and getting data from the server. It works fine putting it inside `await fetch` too. So you do not need to answer my question if you do not want to. However, I would appreciate it, so I will know how to do it in native JavaScript too. –  May 18 '20 at 22:28
0

You can use promise chaining along with fetch api

fetch('/startGame', {
   method: 'POST',
   body: JSON.stringify({username: username}),
   headers: { 'Content-Type': 'application/json' }
})
.then(res => {
   // do something with response

   // make second request
   return fetch('/lookingForAPlayer', {
      method: 'POST',
      body: JSON.stringify({}),
      headers: { 'Content-Type': 'application/json' }
   });
})
.then(res => { /* do something with response */ })
.catch(err => console.log(err));

Keep in mind that second POST request will be sent only after first POST request is successful and client has received the response from the server

Yousaf
  • 27,861
  • 6
  • 44
  • 69
  • Ok, that is what I wanted. It works but I am not sure if I am going to need it now that @ jonrsharpe has just told me that is not a good idea to save `idPlayer` in the server-side. Thanks anyway. It'll be useful if I need it in the future. –  May 18 '20 at 20:01