Asynchronous Programming in JavaScript
Asynchronous programming in JavaScript: Promises, async/await
JavaScript is single-threaded but can handle asynchronous operations.
This prevents blocking execution during long operations.
Reminder: Synchronous vs Asynchronous
Synchronous (blocking) code
console.log("1. Start");
console.log("2. Processing");
console.log("3. End");
Asynchronous (non-blocking) code
console.log("1. Start");
setTimeout(() => {
console.log("2. Asynchronous processing (in 1ms)");
}, 1);
console.log("3. End (displayed before async processing!)");
Callbacks (old style)
Callbacks were the first way to handle asynchronous operations.
Problem: "Callback Hell" with nesting
Simple callback example
function operationAsync(callback) {
setTimeout(() => {
const resultat = Math.random() > 0.5 ? "Success" : "Error";
callback(resultat);
}, 100);
}
operationAsync((resultat) => {
console.log("Callback result:", resultat);
});
Callback Hell Problem
// Code difficult to read and maintain
function callbackHell() {
setTimeout(() => {
console.log("Step 1");
setTimeout(() => {
console.log("Step 2");
setTimeout(() => {
console.log("Step 3");
// And so on...
}, 100);
}, 100);
}, 100);
}
callbackHell();
Promises (ES6)
Promises solve the callback hell problem
Promise states: pending, fulfilled (resolved), rejected
Creating a Promise
function creerPromise(succes = true) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (succes) {
resolve("Operation successful!");
} else {
reject(new Error("Operation failed!"));
}
}, 100);
});
}
Usage with .then() and .catch()
creerPromise(true)
.then(resultat => {
console.log("Success:", resultat);
return "Transformed data";
})
.then(donnees => {
console.log("Transformation:", donnees);
})
.catch(erreur => {
console.error("Error:", erreur.message);
})
.finally(() => {
console.log("Cleanup (always executed)");
});
Error handling
creerPromise(false)
.then(resultat => {
console.log("This line will not execute");
})
.catch(erreur => {
console.error("Error captured:", erreur.message);
});
Promise.all, Promise.race, etc.
Promise.all
// Promise.all: waits for ALL promises to complete
console.log("--- Promise.all ---");
const promiseA = creerPromise(true);
const promiseB = new Promise(resolve => setTimeout(() => resolve("B"), 150));
const promiseC = new Promise(resolve => setTimeout(() => resolve("C"), 200));
Promise.all([promiseA, promiseB, promiseC])
.then(resultats => {
console.log("All results:", resultats); // ["Operation successful!", "B", "C"]
})
.catch(erreur => {
console.error("One of the promises failed:", erreur);
});
Promise.race
// Promise.race: returns the result of the FIRST promise that completes
console.log("--- Promise.race ---");
const promiseLente = new Promise(resolve => setTimeout(() => resolve("Slow"), 300));
const promiseRapide = new Promise(resolve => setTimeout(() => resolve("Fast"), 100));
Promise.race([promiseLente, promiseRapide])
.then(resultat => {
console.log("First result:", resultat); // "Fast"
});
Promise.allSettled
// Promise.allSettled: waits for all promises, even in case of error
console.log("--- Promise.allSettled ---");
const promiseSuccess = Promise.resolve("Success");
const promiseError = Promise.reject(new Error("Error"));
Promise.allSettled([promiseSuccess, promiseError])
.then(resultats => {
console.log("All results (settled):", resultats);
// [{ status: "fulfilled", value: "Success" }, { status: "rejected", reason: Error }]
});
Async/Await (ES2017)
async/await makes asynchronous code more readable
An async function always returns a Promise
Basic async function
async function fonctionAsync() {
try {
console.log("Start of async function");
const resultat1 = await creerPromise(true);
console.log("Result 1:", resultat1);
const resultat2 = await new Promise(resolve =>
setTimeout(() => resolve("Second result"), 100)
);
console.log("Result 2:", resultat2);
return "Function completed";
} catch (erreur) {
console.error("Error in async function:", erreur.message);
throw erreur; // Re-throw the error
}
}
// Calling an async function
fonctionAsync()
.then(resultat => console.log("Return of the function:", resultat))
.catch(erreur => console.error("Final error:", erreur.message));
Comparison Promises vs async/await
With Promises (chaining)
function avecPromises() {
return creerPromise(true)
.then(resultat1 => {
console.log("Promise - Result 1:", resultat1);
return creerPromise(true);
})
.then(resultat2 => {
console.log("Promise - Result 2:", resultat2);
return "Completed with Promises";
});
}
With async/await (more readable)
async function avecAsyncAwait() {
const resultat1 = await creerPromise(true);
console.log("Async - Result 1:", resultat1);
const resultat2 = await creerPromise(true);
console.log("Async - Result 2:", resultat2);
return "Completed with async/await";
}