To return a value from a promise you use it's .then(). The .then() method is not there for you to log the result. It is there for postComparaison() to call to get the result:
function getLastIndice(){
console.log("on appel la fonction get LastIndice");
var requestOptions = {
method: 'GET',
redirect: 'follow'
};
// IMPORTANT! The `return` below in front of the `fetch()` is
// what will return the value to the caller:
return fetch("http://localhost:3000/comparaison/getLastIndice", requestOptions)
.then(response => response.text())
.then(result => {
console.log('code INSIDE THIS THEN executes AFTER we get response : ' + result );
return parseInt(result);
})
.catch(error => console.log('error', error));
console.log('code OUTSIDE THE THEN ABOVE executes BEFORE we get response');
}
This is very important. Code at the bottom of the function executes FIRST. Code inside the then executes LAST.
To clarify let's remove all details from the function:
function getLastIndice() {
// THIS HAPPENS FIRST
console.log('first');
return fetch()
.then(response => response.text())
.then(result => {
// THIS HAPPENS THIRD
console.log('third');
return parseInt(result);
});
// THIS HAPPENS SECOND
console.log('second');
}
The above code will log:
first
second
third
But please note:
function getLastIndice() {
return fetch() // THIS RETURN IS IMPORTANT ! !
.then(r => r.json())
.then(r => parseInt(r));
}
So basically a clean version of getLastIndice() can be written simply as:
function getLastIndice() {
var requestOptions = {
method: 'GET',
redirect: 'follow'
};
return fetch("http://localhost:3000/comparaison/getLastIndice", requestOptions)
.then(x => x.text())
.then(y => parseInt(y));
}
That's all the function needs to be. We don't really need (or want) to catch the error here because we want the caller to be able to detect the error so we simply remove the .catch().
Now that the function works properly here's how you use it in postComparison():
function postComparison() {
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
// Remember, .then() is how getLastIndice() RETURNS its value:
getLastIndice().then(indice => {
var raw = JSON.stringify({
"_id": indice+1, // WE GOT THIS FROM .then of getLastIndice()
"id_User": "2",
"PseudoUser": "bob",
"Titre" : document.getElementById("Titre").value
});
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: raw,
redirect: 'follow'
};
fetch("http://localhost:3000/comparaison", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
}
}
Alternatively you can return the variable raw and process the rest inside another .then(). That's the whole reason Promises were invented - to flatten callback nesting by chaining .then()s:
function postComparison() {
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
// Remember, .then() is how getLastIndice() RETURNS its value:
getLastIndice()
.then(indice => {
var raw = JSON.stringify({
"_id": indice+1,
"id_User": "2",
"PseudoUser": "bob",
"Titre" : document.getElementById("Titre").value
});
return raw; // return this to the `then` below:
})
.then(requestBody =>
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: requestBody, // requestBody comes from raw above
redirect: 'follow'
};
return fetch("http://localhost:3000/comparaison", requestOptions);
})
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
// ^^ NOTE: all the then() are on the same level!
}
If you want postComparison() to return the final result just do the same thing we did with getLastIndice() above: add the return keyword in front of getLastIndice():
function postComparison() {
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
return getLastIndice() // THIS RETURN IS IMPORTANT !
.then(indice => {
var raw = JSON.stringify({
"_id": indice+1,
"id_User": "2",
"PseudoUser": "bob",
"Titre" : document.getElementById("Titre").value
});
return raw;
})
.then(requestBody =>
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: requestBody, // requestBody comes from raw above
redirect: 'follow'
};
return fetch("http://localhost:3000/comparaison", requestOptions);
})
.then(response => response.text())
.then(result => {
console.log(result);
return result; // return the result into the chain of then()
// this return is ALSO IMPORTANT
})
.catch(error => console.log('error', error));
}
An Analogy:
Using Promises you ALWAYS have to remember that the code inside then() happens after the end of the function, not before! It actually makes sense if you think about it.
Say for example you are ordering a Pizza. What usually happens is something like this:
- You call
Restaurant() and order a pizza
pizzaDeliveryGuy(() => will send you the pizza)
- You put down the phone
- You wait for the
pizzaDeliveryGuy()
Note that in the events above the pizzaDeliveryGuy() is the .then() and the Restaurant() makes a Prmoise to send you a pizza (using pizzaDeliveryGuy()). Even though the Restaurant() promised you to deliver the pizza BEFORE you put down the phone the send you the pizza event happens AFTER you put down the phone.
Your confusion is exactly this: not understanding that a promise happens in the future. The pizza delivery guy will send you the pizza after you make the order even though the restaurant promised you the pizza before you put down the phone. Similarly, Promises will execute the .then() callback after the end of the function, not before.
Modern code with async / await:
ECMAScript version 6 introduced two keywords that helps simplify handling asynchrnous code: async and await. They build upon Promise and is basically a special syntax for inlining promises.
Basically if you write something like this:
async function x () {
let y = await z();
console.log(y);
}
Javascript will compile it to something like this:
function x () {
z().then(y => console.log(y));
}
Using async/await we can simplify your code. First we can rewrite getLastIndice() like this:
async function getLastIndice() {
var requestOptions = {
method: 'GET',
redirect: 'follow'
};
let response = await fetch("http://localhost:3000/comparaison/getLastIndice", requestOptions);
let txt = await response.text();
return parseInt(txt);
}
Because we are using await everything in the function above happens in sequence from top to bottom:
async function getLastIndice() {
// THIS HAPPENS FIRST
var requestOptions = {
method: 'GET',
redirect: 'follow'
};
// THIS HAPPENS SECOND
let response = await fetch(URL, requestOptions);
// THIS HAPPENS THIRD
let txt = await response.text();
// THIS HAPPENS LAST
return parseInt(txt);
}
Now we can rewrite postComparison() like this:
async function postComparison() {
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
try {
let indice = await getLastIndice();
var raw = JSON.stringify({
"_id": indice+1,
"id_User": "2",
"PseudoUser": "bob",
"Titre" : document.getElementById("Titre").value
});
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: raw
redirect: 'follow'
};
let response = await fetch("http://localhost:3000/comparaison", requestOptions);
let result = await response.text())
console.log(result);
return result;
}
catch(error) {
console.log('error', error);
}
}
As you can see, async/await is much easier to read for simple sequential code like this. Just don't forget to await the results.
Still, even if you use async/await I think it's critical to understand how Promises work and how .then() work because async/await was built on top of promises. There are some situations where you want two or more things to run in parallel instead of sequentially and that is when you need to go back to promises and callbacks.