1

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.

Onyr
  • 769
  • 5
  • 21
  • `.then(console.log("I want to be after"))` – https://stackoverflow.com/questions/7137401/why-is-the-method-executed-immediately-when-i-use-settimeout – Ry- Oct 30 '19 at 22:53
  • I don't really see the answer being removing the parenthesis in the setTimeout ...? I'm not executing the function, just declaring it inside. Please develop – Onyr Oct 30 '19 at 23:00
  • You *are* executing the function. `console.log("I want to be after")` is a function call expression, and it has to be evaluated to be used as an argument to the `.then()` call. `.then()` is like any other call in this respect. If you wanted to pass it a function, you would use `.then(function () { console.log("I want to be after"); })` (as seen in the linked questions). – Ry- Oct 30 '19 at 23:02
  • Ok, I understood, I edited the question with the remaining interogation – Onyr Oct 30 '19 at 23:23
  • `setTimeout` does not return a promise, so the `await` doesn't know what to wait for. It waits for `undefined` and continues immediately. Later, the timeout fires. – Bergi Oct 30 '19 at 23:25
  • `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- Oct 30 '19 at 23:26
  • @Bergi I don't understand? The SetTimeout is wrapped into an async function which returns a Promise? https://nodejs.dev/modern-asynchronous-javascript-with-async-and-await – Onyr Oct 30 '19 at 23:28
  • @Ry- This means that async is of no use then, in this situation ??? – Onyr Oct 30 '19 at 23:29
  • @Onyr An `async function` only waits for the things that are `await`ed 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 Oct 30 '19 at 23:31
  • OK!!! So I still need the Promise constructor even with async functions... This is a bit strange as I understood async/await should replace Promise and Promise Constructor use... but it makes sense. Thank you ! – Onyr Oct 30 '19 at 23:33
  • Ok, everything is finally fine. Thank you all. This can be considered closed. – Onyr Oct 31 '19 at 01:17

0 Answers0