2

UPDATE: I think the question I have regarding async/await is a little more nuanced than the linked suggestion and have updated the title of the question to hopefully better reflect this. I'm specifically concerned with how to start some asynchronous work that potentially takes a while --but does not impact the majority of a page's logic which needs to happen in sequence-- and then wait for the asynchronous work to complete before moving forward with a subset of the page's logic that does rely upon the asynchronous logic. The answer winds up being essentially the same (await Promise.all), but the clarity provided by the accepted answer for my question was more valuable to me than the linked answer (abstract the sequential logic into its own asynchronous function before using await Promise.all).

I'm having trouble finding out if this is possible in javascript (the comment block marked with "XXX" at the beginning is the code with which I'm struggling (pretend that tasks 1-4 must be executed in order and cannot be parallelized)):

document.addEventListener('DOMContentLoaded', () => {
  // Kick off some asynchronous piece of work that potentially takes some 
  // time (for instance, opening and upgrading an indexedDB) but that should
  // not hold up other work that should happen in the meantime (ie: executing
  // tasks 1-3).
  asynchronousSetup(); // 1000 - 1500 ms of work

  // Do a bunch of other stuff that should happen in sequence and as quickly
  // as possible (to enable meaningful user interaction in the client).
  executeTask1(); // 300 - 400 ms of work
  executeTask2(); // 300 - 400 ms of work
  executeTask3(); // 300 - 400 ms of work

  // XXX Wait for completion of asynchronousSetup() before proceeding with
  // any additional work that is also necessary for meaningful user
  // interaction in the client, but that requires that the work done in
  // asynchronousSetup() is completely finished.
  if (/* asynchronousSetup() complete */) {
    executeTask4(); // Relies on work done in tasks 1-3 and asynchronousSetup()
  }
});

I'm familiar with async/await and promises in javascript, but I haven't seen any demonstrations of their ability to accomplish this sort of thing without --what feels to me like a code smell-- setting an interval or timeout to check for the initialization of some common variable at the point where I want to ensure asynchronousSetup() has completed before firing executeTask4().

It would be really sweet if I could do:

// ...Same initial code as above.

const initialized = asynchronousSetup();

// ...Same intervening code as above.

if (await initialized) {
  executeTask4();
}

assuming that asynchronousSetup() was appropriately decorated with async:

async function asynchronousSetup() {
  // Logic of asynchronousSetup()
}

but I've tried that before with no success.

Thanks, and sorry if this is an obvious one; I haven't had any luck in my searches or my experiments in code. I have a feeling I'm going to feel very dumb once someone points out how to achieve this... but I'll take my knocks; this feels like a substantial hurdle in my understanding that I need to overcome before I can write performant javascript that results in good UX ;p

SheffDoinWork
  • 743
  • 2
  • 8
  • 19
  • 1
    Does this answer your question? [Call async/await functions in parallel](https://stackoverflow.com/questions/35612428/call-async-await-functions-in-parallel) – VLAZ Apr 01 '20 at 21:25
  • 1
    You just need `Promise.all` to wait for all of these to get resolved. `Promise.all([asynchronousSetup(), executeTask1(), executeTask2(), executeTask3()]).then(executeTask4)` or `await Promise.all([asynchronousSetup(), executeTask1(), executeTask2(), executeTask3()]); executeTask4()` in an async function – VLAZ Apr 01 '20 at 21:27
  • @VLAZ Your linked question comes close to answering my specific question, but I think it's more directly answering the question of how to parallelize work with async/await in general. It doesn't demonstrate as clearly how to kick off an async operation and then do some synchronous work while pausing at a certain point to ensure the async work has completed. rfestag's answer below does a really good job of succinctly demonstrating that. – SheffDoinWork Apr 02 '20 at 14:45
  • @VLAZ Oddly enough, the second highest-voted answer in the linked question suggests that what I tried with ```const initialized = asynchronousSetup(); ... if (await initialized) { ...``` should have worked. Maybe not that specific approach, but something like it. I wonder if there was another issue in my experimentation with it that caused me to think that was impossible. – SheffDoinWork Apr 02 '20 at 14:47

1 Answers1

5

If I'm following you correctly, you have to do asyncSetup and 3 tasks concurrently (but those 3 tasks must be done in order). Only after all 4 of those tasks are done do you want to move on to the last task. Something like this seems to do what you're asking:

//Provide an async function that does your 3 tasks in the correct order
const doTasks = async () => {
  await executeTask1(); // 300 - 400 ms of work
  await executeTask2(); // 300 - 400 ms of work
  await executeTask3(); // 300 - 400 ms of work
}
document.addEventListener('DOMContentLoaded', async () => {
  //Do the setup and the tasks concurrently
  await Promise.all([asynchronousSetup(), doTasks()])
  //Once all of the previous tasks are done, do the last task
  executeTask4()
});

This assumes that all of your tasks are all async, or that the return Promises.

rfestag
  • 1,913
  • 10
  • 20
  • Thank you; this is very clean and served as kind of a "eureka!" moment for me. I've been stuck on the thinking that async/await have completely done away with the need for ever using the promise syntax in code, and I was thinking that there would/should be a way to do this entirely with async/await. I'll keep Promise.all in the toolkit alongside async/await and that should address some of the behaviors I was struggling to bring to life through my code. Thanks again :) – SheffDoinWork Apr 02 '20 at 14:55