1

I need some suggestions in my angular 6 project and tips for best practice.

Below you can see some pseudo code (please ignore any typos) but it's basically what is happening. The project goes through a couple of steps to get new and fresh data and process that before showing the user. What I want to do is to make it run through all step 1 until it is finished, then onto step 2, once it is done it goes to step 3 and so on. This is because some of the steps require the response from the previous step before they can make their request which means I need to wait for each step to finish before moving on to the next one. But I have a little problem with the asynchronous functions.

var token;

mainFunction(){
    step1();
    console.log("Done with step 1");

    step2();
    console.log("Done with step 2");

    step3();
    console.log("Done with step 3");
}

step1(){
    console.log("Step 1...");
    var data1 = getData();
    // Does things with data1
}

step2(){
    console.log("Step 2...");
    var data2 = getData();
    // Does things with data2
}

step3() {
    console.log("Step 3...");
    var data3 = getData();
    // Does things with data3
}

async getData(){
    await getAccessToken();

    var result;

    console.log("Getting data...");

    // Makes a request to an API.
    this.http.post("URL", token)
    .map(response => response.json())
    .toPromise()
    .then((response: any) => {
        console.log("Got the data!");

        // Processing the response
        result = response;
    }
    return result;
}

async getAccessToken(){
    console.log("Getting access token...");

    let accessToken = await getToken(); //Returns a Promise

    this.token = accessToken;
    console.log("Got the token!");

    return Promise.resolve(true);
}

The problem started with getToken() inside the getAccessToken function. That is an asynchronous function that returns a promise, which means it doesn't wait for the response. No problem, just set an await and it works fine!

But even if the getAccessToken() now waits for the getToken() to finish, getData() doesn't wait for getAccessToken() to finish waiting for getToken(). Solution? I returned a Promise and put await inside getData(). But I didn't solve the problem I only moved it.

Right now the getData() now waits for the accessToken to be finished before doing the request but step1, step2 and step 3 doesn't wait. Is the solution to return a promise all the way and set await on every function? I hope there is a cleaner way to do it and just set await where it actually needs to wait and everything will stop and wait for that to finish.

Is there a clean way of doing that? What is best practice?

This is the output I want:

  • Step 1...
  • Getting acces token...
  • Got the token!
  • Getting data...
  • Got the data!
  • Done with step 1
  • Step 2...
  • Getting access token...
  • Got the token!
  • Getting data...
  • Got the data!
  • Done with step 2
  • Step 3...
  • Getting Access token...
  • Got the token!
  • Getting data...
  • Got the data!
  • Done with step 3

This is the output I get:

  • Step 1...
  • Getting access token...
  • Done with step 1
  • Step 2...
  • Getting access token...
  • Done with step 2
  • Step 3...
  • Getting access token...
  • Done with step 3
  • Got the token!
  • Getting data...
  • Got the data!
  • Got the token!
  • Getting data...
  • Got the data!
  • Got the token!
  • Getting data...
  • Got the data!
Johan C.
  • 21
  • 1
  • 6

1 Answers1

0

Is the solution to return a promise all the way and set await on every function?

Yes (but note that you don't need to do it explicitly as you have in getAccessToken, more below). If a function relies on the result of an asynchronous function, then that function must also be asynchronous. This bubbles all the way up.

If you want mainFunction to process step1, step2, and step3 in order, and they rely on asynchronous results, then they must be asynchronous, and mainFunction must be asynchronous (and anything using it must be asynchronous):

async function mainFunction() {
    console.log("mainFunction start");
    await step1();
    console.log("step1 done");
    await step2();
    console.log("step2 done");
    await step3();
    console.log("step3 done");
    console.log("mainFunction done");
}
async function step1() {
    await getData();
}
async function step2() {
    await getData();
}
async function step3() {
    await getData();
}
async function getData() {
    await getAccessToken();
    return Math.floor(Math.random() * 1000);
}
async function getAccessToken() {
    await asyncStandIn();
}
function asyncStandIn() {
    return new Promise(resolve => setTimeout(resolve, 800));
}

// Top level entry
(async () => {
    mainFunction();
})().catch(error => {
    console.error(error);
});

Re getAccessToken: Just making it an async function as you have means it always returns a promise. No need for return Promise.resolve(true);, you can just remove that line. (It's a bit odd that a function called getAccessToken doesn't return [the promise of] an access token, though.)

More reading; my take was that voting to close your question as a duplicate of the following wouldn't be the right thing, but others may differ:

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Thanks! Yeah, When I have searched around here I only see one level of function calls (if that is the case then async and await does the trick) but here I have 3 levels of function calls that ends with an asynchronous function. But this clears everything up, Thank you! – Johan C. Oct 30 '18 at 10:58
  • @JohanC. - Yup. That means if the intermediary functions need to wait for that one lower down, they too have to be asynchronous, all the way up. – T.J. Crowder Oct 30 '18 at 10:59