Chapter 11
Async JavaScript
Learning Objectives
- Understand asynchronous code
- Work with Promises
- Use async/await syntax
- See how MixMind handles file loading and analysis
What is Async?
Some operations take time: loading files, network requests, analyzing audio. If we wait for each to finish before continuing, the page would freeze.
Asynchronous code lets JavaScript start a long operation and continue running other code while waiting.
// BAD - blocks everything
const buffer = loadAudioFile("song.mp3"); // Page freezes!
analyzeAudio(buffer); // Has to wait
// GOOD - doesn't block
loadAudioFile("song.mp3").then(buffer => {
analyzeAudio(buffer);
});
console.log("This runs immediately!");
Promises
A Promise represents a value that will be available in the future. It can be:
- Pending - Still working
- Fulfilled - Completed successfully
- Rejected - Failed
// Creating a Promise
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
const success = true;
if (success) {
resolve("Data loaded!");
} else {
reject("Error occurred");
}
}, 2000);
});
// Using a Promise
promise
.then(result => {
console.log(result); // "Data loaded!"
})
.catch(error => {
console.error(error);
});
// Chaining Promises
loadFile("song.mp3")
.then(buffer => decodeAudio(buffer))
.then(audioData => analyzeAudio(audioData))
.then(analysis => displayResults(analysis))
.catch(error => console.error("Failed:", error));
Async/Await
async/await is modern syntax that makes async code look synchronous:
// Async function
async function processTrack(file) {
try {
// await pauses until Promise resolves
const buffer = await loadFile(file);
const audio = await decodeAudio(buffer);
const analysis = await analyzeAudio(audio);
return analysis;
} catch (error) {
console.error("Processing failed:", error);
throw error;
}
}
// Calling async function
processTrack("song.mp3")
.then(result => console.log(result))
.catch(error => console.error(error));
// In event handler
uploadBtn.addEventListener("click", async () => {
const file = fileInput.files[0];
const analysis = await processTrack(file);
updateUI(analysis);
});
// Multiple async operations
async function processAllTracks(files) {
const promises = files.map(file => processTrack(file));
const results = await Promise.all(promises);
return results;
}
🎵 MixMind Connection
How MixMind Uses Async
// Loading and analyzing audio
async function loadAndAnalyze(file) {
// Read file
const arrayBuffer = await file.arrayBuffer();
// Decode audio
const audioContext = new AudioContext();
const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);
// Analyze (takes time)
const bpm = await detectBPM(audioBuffer);
const key = await detectKey(audioBuffer);
const energy = await calculateEnergy(audioBuffer);
return { file, audioBuffer, bpm, key, energy };
}
// Processing multiple files
async function handleUpload(files) {
const results = [];
for (const file of files) {
updateProgress("Analyzing " + file.name);
const result = await loadAndAnalyze(file);
results.push(result);
}
return results;
}
// WebAssembly calls
async function separateStems(audioBuffer) {
const wasmModule = await loadWasmModule();
const result = await wasmModule.separate(audioBuffer);
return result;
}
Exercise 11.1: Practice
Goal: Apply what you've learned in this chapter
Try the concepts from this chapter in your browser's console or a simple HTML file. Experiment with the code examples and modify them to see what happens.
📝 Quick Reference:
Review the key concepts from this chapter and make sure you understand each one before moving to the next chapter.