I already posted a question on this subject here on StackOverflow. Following the recommendations, I have tried to simplify my question.
I don't understand how to make synchronous code with Promises and their new polished version using async/await, despite the fact I have read and tried different approaches.
Here, I link some good documentation on the subject, in case it can help people in the future. Basically, Promises are an answer to callback hell and a way to make code execute after some other code has been executed, making things happening synchronously since JavaScript (hence Node.js) is asynchronous by nature. Async/await is built on top of Promises and simplify the code.
understanding JavaScript Promises
modern JavaScript with async/await
Async/await explained with examples
why moving from Promises to async/await
Despite I seem to understand the concept, I can't explain the results I obtain. To better my comprehension, here is a test file using node.js -v v8.10.0
/* This file try to use Promises and async/await to run code synchronously */
/* declaration of some Promisified functions */
const doSomethingAsync = () => { // direct declaration using new Promise and Promise.resolve()
return new Promise(resolve => { // This is just a promise, necesiry to wait for it
setTimeout(() => resolve('I want to be first'), 3000);
});
};
const test1 = async () => { // indirect Promise declaration usind async
return setTimeout(() => console.log("test1, I want to be executed first"), 3000); // async => the function returns a promise hence return a resolve,
}; // we should use await to wait for the Promise.resolve()
/* create intermediate calling functions making code synchronous to use console.log() properly */
const doSomething = async () => {
console.log( await doSomethingAsync());
};
const callTest = async () => {
console.log("hope to be executed before test1() resolve");
await test1();
console.log("hope to be executed after test1() resolve");
}
/* hope to run code synchronously in the following using .then() keyword */
console.log('1');
doSomething();
console.log('2');
callTest();
console.log('3');
doSomething()
.then(console.log("I want to be after"))
.catch(error =>{
console.log(error);
});
console.log('4');
console.log( doSomethingAsync().then(console.log("I want to be after too")) );
console.log('5');
// hope to run code synchronously in the following using await keyword
(async () => {
let test2 = await doSomethingAsync();
let test3 = await doSomething();
await test1();
console.log(`value doSomethingAsync: ${test2}`);
console.log(`value doSomething: ${test3}`);
})();
console.log('6');
What I expect is to see the code putted into the .then() keyword to be executed synchronously after Promise.resolve() fire... but it's not what I observe. See below the output of the program in my terminal:
ʘ node test_promises.js
1
2
hope to be executed before test1() resolve
3
I want to be after
4
I want to be after too
Promise { <pending> }
5
6
hope to be executed after test1() resolve
test1, I want to be executed first
I want to be first
I want to be first
I want to be first
value doSomethingAsync: I want to be first
value doSomething: undefined
test1, I want to be executed first
From the output, it is clear that .then() runs before the code inside the called function.
from StackOverflow
The success or the error handler in the then function will be called only once, after the asynchronous task finishes.
It seems not to be the case. Hence my question is straightforward:
Question: Why is .then() called before the asynchronous tack finish, and how to properly code with Promises, .then() and async/await (which is supposed to replace then)?
EDIT
From the answer of the community, I understand that .then() fires directly when the values passed to it are not callback functions. Hence, by modifying the .then() like so .then(function() {console.log("I want to be after")} )
Ok, I had not understood. I get
ʘ node test_promises.js
1
2
hope to be executed before test1() resolve
3
4
Promise { <pending> }
5
6
hope to be executed after test1() resolve
test1, I want to be executed first
I want to be after too
I want to be first
I want to be first
I want to be after
I want to be first
value doSomethingAsync: I want to be first
value doSomething: undefined
test1, I want to be executed first
I still do not understand why the console.log()s fire before the await function call in
const callTest = async () => {
console.log("hope to be executed before test1() resolve");
await test1();
console.log("hope to be executed after test1() resolve");
}
Thanks for the patience of the community
EDIT 2
From the answers of the community:
An async function only waits for the things that are awaited inside its code. It does not automagically recognise any calls that do something asynchronous. You need to explicitly promisify setTimeout to make it work with promises. – Bergi ANSWER 2: return setTimeout(() => console.log("test1, I want to be executed first"), 3000) isn’t correct, because setTimeout doesn’t return a promise. Converting functions that use callbacks, like setTimeout, without using other helper functions is a little wordy: return new Promise(resolve => { setTimeout(resolve, 3000); }); – Ry-♦
This means the correct code is the following:
// declaration of some Promisified functions
const doSomethingAsync = () => {
return new Promise(resolve => {
setTimeout(() => resolve('I want to be first'), 3000);
});
};
const test1 = async () => { // IMPORTANT CORRECTION: use Promise constructor
return new Promise(resolve => { setTimeout( () => {resolve("test1, I want to be executed first")}, 3000); }); // actuallu async do not transform the return
}; // function into a Promise
// create intermediate calling functions making code synchronous to use console.log() properly
const doSomething = async () => {
console.log( await doSomethingAsync());
};
const callTest = async () => {
console.log("hope to be executed before test1() resolve");
const resultTest1 = await test1(); // IMPORTANT CORRECTION: declare a variable to return the value of the executed function when exec is over, using await
console.log(resultTest1);
console.log("hope to be executed after test1() resolve");
}
// hope to run code synchronously in the following using .then() keyword
console.log('1');
doSomething();
console.log('2');
callTest();
console.log('3');
doSomething()
.then(function() {console.log("I want to be after")} ) // IMPORTANT CORRECTION: declare a callback function instead of executing the function
.catch(error =>{
console.log(error);
});
console.log('4');
console.log( doSomethingAsync().then(function() {console.log("I want to be after too")}) );
console.log('5');
// hope to run code synchronously in the following using await keyword, THIS IS THE "RIGHT" WAY TO USE ASYNC/AWAIT
(async () => {
let test2 = await doSomethingAsync();
let test3 = await doSomething();
await test1(); // this is the last await, it will be the last executed code
console.log(`value doSomethingAsync: ${test2}`);
console.log(`value doSomething: ${test3}`);
})();
console.log('6');
A special thank to everyone that helped. I hope this will be useful.