Detect when JS function has completed

I’m building a React Guitar, and on page load, I’m creating the wav files for the sounds, which takes a couple of seconds. I’m unsure how to implement something like a “loading” bar.

I’ve struggled with this problem in several projects but never quite got my head around it. Do I need await/async or promises for that?

Without seeing any code it would be hard to suggest something specific, but, yes, you’ll need either await/async, promises or callback.

I have a codesandbox here: https://codesandbox.io/s/condescending-black-1lc9z

So, in the utils folder, you’ll find a playGuitar.js., which imports audioFiles.js, which exports an object with references to all wavs.

I’d be interested in the callback solution, how would I write that?

Here’s an example with a callback (check console): https://codesandbox.io/s/headless-frost-ce8rs (on my computer file loading takes less than 300ms).

Awesome :smiley:
Digesting that with pen & paper will open some eyes over here

After making it work with a callback, I’m now trying to do the same with async/await instead. For easier reference, here’s the setup:

createAudioFiles.js

export function createAudioFiles(){
    // big block of code
    return fileCache
}

playGuitar.js

import {createAudioFiles} from '../utils/createAudioFiles.js';

/* this is what I tried: */
const getAudio = async function(){
    let result = await createAudioFiles();
    console.log(result) // result is an empty fileCache
    return result;
}
const audioFiles = getAudio();

console.log(audioFiles); // Promise(pending)

I’m obviously missing something. I’ve read that even if my async function doesn’t explicitly return a Promise, it will automatically be wrapped in a Promise that will resolve to the value it’s returning.

Why is result an empty fileCache? Shouldn’t the await keyword make sure that result is assigned AFTER the complete fileCache has been created and returned from my createAudioFiles function?

Yes, but createAudioFiles is not an async function.

Ugh. Alright I’ve modified the code like this:

createAudioFiles.js

export async function createAudioFiles(){
    // big block of code
    return await fileCache
}

It doesn’t help. In fact I don’t even see a difference in my console.logs (I’ve added another one where I log audioFiles with a timeout after 2 seconds). At that point, it’s a Promise with status fulfilled. But when I inspect it with the dev tools, it still holds an empty fileCache. I think I need to “unwrap” that Promise somehow to get my fileCache. I just don’t know how.

I thought I’m doing it exactly like it is described in the first example of the docs:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

I actually find that particular article terribly confusing. It’s not the first time I’m digging my way through it but I just. don’t. get. it.

They write that using async/await allows it to write async code without the explicit use of Promises. But later in all their examples, they’re doing exactly that.

They also write that the difference between return fileCache and return await fileCache is that return await will WAIT for fileCache to resolve. Why isn’t that happening in my code?

Here’s an async/await version: https://codesandbox.io/s/green-resonance-1hil2 (I added 2s artificial delay)

Async only awaits for promises.

return await foo is redundant. In an async function, it means exactly the same thing as return foo, and in a non-async function, it’s a compile error.

You’re giving me headaches :woozy_face:

Why are you returning a promise from createAudioFiles() now? I thought that wasn’t necessary with async/await?

Thanks for the edit, nonetheless. I guess I’ll have to learn it the hard way, which means going through the docs and code along with every single example until it finally enters my brain.

Not really, here’s the part from the docs:

This highlights the subtle difference between return foo; and return await foo;return foo immediately returns foo and never throws, even if foo is a Promise that rejects. return await foo will wait for foo to resolve or reject if it’s a Promise, and throws before returning if it rejects.

Probably only relevant when you have to handle errors but still good to know.

The promise in createAudioFiles is just to create an artificial delay. It is not returned.

OH alright this explains why it takes two seconds longer for the files to be created/the function to return.

I’m still going through your edits and I’m still super confused, for example as to why you’ve moved the execution of createAudioFiles() into my createGuitarNotes() function, those two are totally unrelated, and I’m still puzzled why my fileCache always seems to be just an empty fileCache when I log it, no matter where or when I log it…

Brain just needs more time (await click)

Because you can only await inside async function. Another option would be to create an IIFE.

createGuitarNotesArr is the only place where audioFiles is used, so to me it looks like they are totally related.

That’s why I had created a small getAudio() function in my original approach, so at least I got that half-right… I’ve merged your solution into that, because

isn’t quite right, createGuitarNotesArr() only creates an array for the fretboardValsToNote() function (sort of a look-up table), while my audioFiles are used by the playNote function which in turn is used by all functions I’m exporting, … but I’m just nitpicking here.

Point is it works now with my modified getAudio() function.

This works:

let audioFiles;
const getAudio = async function(){
    audioFiles = await createAudioFiles();
}
getAudio();

This doesn’t:

const getAudio = async function(){
    let result = await createAudioFiles();
    return result
}
const audioFiles = getAudio();

I’m not 100% sure I’ve understood why yet, but it’s good to know what I’ve done wrong (here, and whenever I tried something with async/await before).

Also found out why my fileCache seemed to be empty. I’m just stupid, some entries must be empty because a guitar doesn’t have all the notes that a full 88-key piano has, and the fileCache is built with identical structure for both instruments.