0

I am converting an async.auto flow to async await code. To simplify my question say I have a set of tasks and a list of dependencies of these tasks on each other how can I convert this to async await code. Here is an example I feel which will cover all the cases(correct me if it does not).

Set of tasks - a(), b(), c(), f(), d(resultOfA, resultOfB), e(resultOfB, resultOfC), g(resultOfF, resultOfE) Here to execute d we need values returned from a and b, and to execute e we need those of b and c, for g we need e and f.

Note that I want to complete all the tasks as early as possible

Edit: Adding a sample async auto flow which I need to convert

async.auto({
    a: function(callback) {
        setTimeout(() => {
            let resA = 3;
            callback(null, resA);
        }, 1000);
    },
    b: function(callback) {
        setTimeout(() => {
            let resB = 4;
            callback(null, resB);
        }, 1000);
    },
    c: function(callback) {
        setTimeout(() => {
            let resC = 5;
            callback(null, resC);
        }, 1000);
    },
    d: ['a', 'b', function(results, callback) {
        setTimeout(() => {
            //following line represents some computations which depends on resA and resB
            resD = results.a + results.b;
            callback(null, resD);
        }, 1000);
    }],
    e: ['b', 'c', function(results, callback) {
        setTimeout(() => {
            resE = results.b + results.c;
            callback(null, resE);
        }, 1000);
    }],
    f: function(callback) {
        callback(null, resF);
    },
    g: ['e', 'f', function(results, callback) {
        setTimeout(() => {
            resG = results.e + results.f;
            callback(null, resG);
        }, 1000);
    }]
}, function(err, results) {
    if (err) {
        console.log('err : ', err);
    }
    console.log('results : ', results);
});

I am aware of how to run tasks in parallel and in series from these three questions -

  1. way to run tasks in parallel using async/await
  2. way to take results from the tasks running in parallel
  3. a comparison of using Promise.all() and async await for running tasks in parallel
NUMBART
  • 52
  • 9
  • Where's the code you've written to solve this problem? You should add that to your question as a [mcve]. – Andy Oct 12 '21 at 16:38
  • When you write `await` expressions for asynchronous operations, the result is the actual result from the operation. The whole point of `await` is to make coding as you describe easy and natural; there's really nothing special you have to do. – Pointy Oct 12 '21 at 16:40
  • Yes @Andy will add this to make it clearer. – NUMBART Oct 12 '21 at 17:04

1 Answers1

1

Promises only complete once.

async function foo() {
  a = some_promise_factory();
  b = some_promise_factory();
  c = some_promise_factory();
  f = some_promise_factory();
  d = ab(a, b) // the promise resulting from ab is created
               // *before* that from bc, as it is assigned to d
  e = bc(b, c) // doesn't matter if promise b is used again
  g = ef(e, f) // an 'await promise_e' in ef won't resolve
               // until e is resolved, which won't resolve until
               // bc resolves, which won't resolve until
               // both 'await promise_b' and 'await promise_c' ..

  // can await any promise in an async function..
  return await g;
}

Then inside ab, bc, ef, for example. Having the await inside is different than ab(await a, await b); if the await is applied to the arguments first, the call won't be made until those are resolved. Pick the form that works best for the given task.

async function ab (promise_a, promise_b) {
  return (await promise_a) + (await promise_b) + 1;
}

async function bc (promise_b, promise_c) {
  return (await promise_b) + (await promise_c) * 2;
}

async function ef (promise_e, promise_f) {
  return (await promise_e) + (await promise_f) / 3;
}

While an async function implicitly returns a promise, a normal function returning a Promise is also sufficient.

While the above, without forcing resolving in arguments, is "the most parallel" (fsvo "parallel"1, depending on promise sources), it's not always needed and will be slower in the cases when it's trivially not needed. If a call doesn't involve IO, or related continuations, it can probably avoid being async or involving promises.

1It's probably better to consider such concurrent rather than parallel.

user2864740
  • 60,010
  • 15
  • 145
  • 220
  • Thanks @user2864740, this answers my question. However would like to ask this, in `ab(await a, await b);` will any subsequent calls be made in the main function to bc and ef while ab is waiting to get called or those will not be called too until ab gets called? – NUMBART Oct 12 '21 at 17:58
  • `ab(await a, await b)` is equivalent to `xb = await a; xb = await b; ab(xa, xb)` — that is the arguments are evaluated left-to-right and the function is only called after the arguments are evaluated (which implies resolved for `await` expressions). Without the `await` there, it is the promises themselves that are the result of evaluating the simple variable expressions. Keep in mind that even though async/await allows concurrent code, it is not very precise to consider “threads”. – user2864740 Oct 12 '21 at 18:28