La programmation asynchrone moderne en JavaScript
Romuald THION
Semestre pair 2022 UNC
return ne permet pas de renvoyer de valeur
throw dans un cas de succèssetTimeoutfunction throttle(funct, delay) {
let waiting = false;
return function (...args) {
if (!waiting) {
waiting = true;
setTimeout(() => {
waiting = false;
}, delay);
return funct(...args);
}
};
}Le décorateur throttle, une variante de memo avec remise à zéro par une alarme.
Ou comment éviter la pyramid of doom
L’interface Promise représente un intermédiaire (proxy) vers une valeur qui n’est pas nécessairement connue au moment de sa création. Ainsi, des méthodes asynchrones renvoient des valeurs comme les méthodes synchrones, la seule différence est que la valeur retournée par la méthode asynchrone est une promesse (d’avoir une valeur plus tard).
Ce qui change : au lieu de passer le callback en paramètre de la fonction asynchrone, on va passer le callback à l’objet Promise renvoyé par la fonction.

PromisePour créer un Promise, on doit passer une fonction d’ordre supérieure qui elle-même prend deux fonctions en paramètre, nommées par convention :
resolve qui va résoudre en succès (fulfilled)reject qui va résoudre en échec (rejected)Attention l’environnement fixe resolve et reject (code natif) et appelle l’exécuteur immédiatement (exemple)

Les méthodes then(callback) et catch(callback) renvoient des promesses qui peuvent être chaînées à leurs tours.
Le chainage donne un style linéaire qui évite une imbrication des traitements (la pyramid of doom)

Promise.prototype.then(fn) renvoie une promesse :
fn retourne une promesse R dont le résultat sera utilisé quand elle sera résolu ,fn retourne une valeur R qui sera transformée automatiquement en une promesse immédiatement résolue.PromisePromise : un exempleconsole.info("Start");
Promise.resolve(1)
.then(inc)
.then((_) => Promise.reject(new Error("Broken")))
.then(inc) // /!\ sauté /!\
.catch((err) => {
console.error(err);
return 42;
}) // /!\ attention au retour /!\
.then(inc)
.finally(() => console.log("Done"));
console.info("End");Qu’est-ce qui s’affiche ? (source)
thenfn n’est pas une fonction :
Promise.resolve(42).then(1).then(console.log)
42 et pas 1then qui sera déclenché au prochain tour
const p = Promise.resolve(42);p.then(() => p.then(() => console.log(0)));
0setTimeout manuellefunction timedValue(value, delay) {
function executor(resolve, reject) {
setTimeout(() => resolve(value), delay);
}
return new Promise(executor);
}
const p = timedValue(1000, "Success!");
// on enchaine ici 3 callbacks sans imbrication
p.then((str) => "OK! " + str)
.then((str) => str + " Done!")
.then((str) => console.log(str));La promisification consiste à transformer une API par callback en une API qui renvoie une Promise.
function promisify(funct) {
// wrapper (*)
return function (...args) {
return new Promise((resolve, reject) => {
// custom callback/executor (**)
function callback(err, result) {
if (err) reject(err);
else resolve(result);
}
args.push(callback); // append custom callback
funct.call(this, ...args); // call the original function
});
};
}// avec API callback
const wait = (delay, value, cb) => setTimeout(() => cb(null, value), delay);
wait(1000, 42, (err, res) => (err ? console.error(err) : console.log(res)));
// avec Promisification
const waitPromise = promisify(wait);
waitPromise(1000, 42).then(console.log).catch(console.error);La bilbiothèque standard Node.js propose les outils util.promisify et util.callbackify.
PromiseDes méthodes de classe, pas d’instances
The
Promise.all()method returns a singlePromisethat resolves when all of the promises in the iterable argument have resolved.The
Promise.allSettled()method returns a promise that fulfills after all of the given promises have either fulfilled or rejected.
Exemple, lancement de trois promesses en parallèle:
Promise.any()takes an iterable of Promise objects. It returns a single promise that fulfills as soon as any of the promises in the iterable fulfills, with the value of the fulfilled promise.The
Promise.race()method returns a promise that resolves or rejects as soon as one of the promises in the iterable resolves or rejects
Méthodes de classe pour des promesses immédiatement résolues ou rejetées
reject/resolve dans l’exécuteur
fetchhttps://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
The Fetch API provides an interface for fetching resources (including across the network). It will seem familiar to anyone who has used XMLHttpRequest, but the new API provides a more powerful and flexible
fetchstring, une URL ou une RequestPOST, PUT ou PATCH, le body est passé dans les options, avec le type de méthodepython -m http.server ou LiveServer dans le dossier de travailasync-download.js pour que le contenu du fichier dont le nom est passé dans l’input soit affiché dans la balise codeasync et awaitasync / awaitSont là pour faciliter l’utilisation des promesses :
async / await en PromiseLes await sont à peu près équivalents à une ré-écriture de code dans le then des Promise
Pour maîtriser async / await, il faut maîtriser les Promise !
setTimeoutfunction timeout(ms) {
return new Promise((resolve) => setTimeout(() => resolve("Get Up!"), ms));
}
async function sleep() {
const r = await timeout(3000);
console.info(r);
return r;
}
console.log("Before");
await sleep(); // /!\ await SUSPEND l'EXECUTION /!\
console.log("After");Attention à ne pas mettre des await de partout !
async / PromiseExemple Google Web Fundamentals
async-download.js en utilisant async/await