1

I need to run two (or more) lines of code in sequence in vanilla javascript.

Each invokes calls to routines (aka top level functions, which have a purpose of performing procedural steps rather than calculating a result). These in turn call multiple others.

function fMasterProcedure() {
    fSubProcedure1();
    fSubProcedure2();
    ... etc
}

Suppose the code for fSubProcedure1() is as follows (for this illustration):

function fSubProcedure1() {
    fSubSubProcedure1_1();  // Normal
    fSubSubProcedure1_2();  // Async
    fSubSubProcedure1_3();  // Normal
    fSubSubProcedure1_4();  // Async
    fSubSubProcedure1_5();  // Normal
}

This is literally the same question as here how to run sequence functions in javascript, although the answers provided there do not show how to do it, and there have been syntax updates in the years since in relation to promises and asynchronous functions.

These days the answer seems to be promises and async/await... or is it just callbacks without using promises?

I have read many descriptions and tutorials on promises, including here.

However, I end up with code like this:

function fMasterProcedure() {
    return (new Promise(function(resolve, reject) {
        fSubProcedure1();
        setTimeout(function () {
            resolve();
        }, 0);
    })).then(function(result) {
        fSubProcedure2();
    });
}

As you can see, it adds 400% more lines unnecessarily and still doesn't work reliably.

Is there a more efficient way to write this, or a more appropriate way?

(The requirement is to run fSubProcedure2 after fSubProcedure1 (and any of its child processes) are completed in full. I am trying to move from "that's not how JS works" to "here's how to make JS achieve that requirement").

I'm trying to get the good understanding so I can apply it to a whole project approach - there are many examples within, of each.

17
  • 1
    Have you looked into "Continuation Passing Style?" Commented Aug 23, 2020 at 16:28
  • 2
    Your original code should work just fine, unless fSubProcedure1 does something asynchronous. If it does something asynchronous, please post the code of fSubProcedure1 so we can show how it can be chained properly Commented Aug 23, 2020 at 16:28
  • 1
    @ed2 No you didn't. All you did in your "400% more lines" snippet was to wrap an artificial setTimeout(…, 0) in a promise and defer the fSubprocedure2 call until after that. If the subroutines do something asynchronous, they must return promises (rewrite their code if they don't). Then it's as simple as async function fMasterProcedure() { await fSubProcedure1(); await fSubProcedure2(); } Commented Aug 23, 2020 at 16:44
  • 1
    @ed2 No, all you need to do is to make it async which causes it to automatically return a promise. You do never need the new Promise constructor unless you are interfacing with callback code. But all your subprocedures, and their subprocedures, should use async/await for asynchronous code. Commented Aug 23, 2020 at 16:59
  • 1
    That's it, provided your functions return promises, otherwise await will not wait that much ;-) Commented Aug 23, 2020 at 17:11

1 Answer 1

1

If fSubProcedure1 and fSubProcedure2 are two asynchronous functions and you wanna execute them one after the other then try to go for something like :

async function fMasterProcedure() {
    await fSubProcedure1();
    await fSubProcedure2()
}
// to execute the fMasterProcedure function
fMasterProcedure().then(console.log).catch(console.error);
//replace console.log and console.error with your appropriate callbacks

Example :

// returns Promise<number>
function fSubProcedure1() {
    console.log("runs first");
    return Promise.resolve(2*2);
}
// returns void
function fSubProcedureNormal() {
    console.log("runs second");
    //returns nothing
}
// returns number which gets converted to Promise<number>
async function fSubProcedure2() { 
    console.log("runs third");
    return 2*4;
}
async function fMasterProcedure() {
    let a = await fSubProcedure1();
    fSubProcedureNormal();
    let b = await fSubProcedure2();
    return `${a} : ${b}`;
}

fMasterProcedure().then(console.log).catch(console.error);

One important point... You would wanna try and catch error inside fMasterProcedure for every await

Resources :

async function

async await

Check out these resources to learn more

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks. What does line 3 do? If my fSubProcedure1 does not return anything, does line 3 make it into a promise... it seems the important thing I need is to be waiting for a promise, not so much to care what the returned result is rather than when it is returned if that sounds right...
Should the subprocedure functions be declared as async like async function fSubProcedure1() { and async function fSubProcedure2() { in order to make them promises that the master procedure will wait for? Thanks.
any function which is declared async or returns a Promise can be handled with await keyword. await can only be used in async functions. Also It does't matter what your function returns. It will wait for the function to finish execution
I edited my answer. Hope that'll make things easier for you to understand. async just converts whatever return type to Promise<return type> and await is just used to wait for the Promise to resolve.
Thanks @Gray Hat, I will test out your answer on my code and update this with the results once done.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.