JavaScript : un langage synchrone ou asynchrone ?
“P’têt ben qu’oui, p’têt ben qu’non”, j’ai envie de vous dire ! JavaScript est en fait un langage à la fois synchrone et asynchrone.
JavaScript un langage principalement synchrone
Avec JavaScript, les instructions sont exécutées de manière séquentielle, une après l’autre, dans l’ordre dans lequel elles sont écrites. Cela signifie que chaque instruction doit être complètement terminée avant que l’instruction suivante puisse être exécutée. Voici un exemple de code synchrone :
function greet(name) {
return "Bonjour, " + name + "!";
}
var message = greet("John");
console.log(message);
Dans ce cas de figure, l’exécution des instructions bloque l’exécution des instructions suivantes jusqu’à ce qu’elles soient terminées.
Du coup vous vous doutez que si une instruction prend du temps à s’exécuter, elle bloque l’exécution du reste du programme, ce qui peut entraîner des temps d’attente et une utilisation inefficace des ressources et donc des performances réduites. Pas génial ! ☹️
Plot twist : JavaScript également capable d’exécuter des opérations asynchrones
Pour gérer les opérations asynchrones et les tâches longues de manière plus efficace, de nombreux langages de programmation, y compris JavaScript, offrent des mécanismes pour permettre une exécution asynchrone / non bloquante du code.
L’asynchronisme en JavaScript est géré principalement grâce à des fonctions de rappel (callbacks), des promesses (promises) et des fonctions asynchrones (async/await) introduites dans les versions récentes d’ECMAScript (ES6+).
Cela est particulièrement utile lors de l’exécution de tâches longues ou potentiellement bloquantes, telles que les requêtes réseau, les accès aux fichiers …
Du coup c’est quoi les callbacks
Cela permet de spécifier une fonction à exécuter une fois qu’une opération asynchrone est terminée. Voici un exemple concret :
function greet(name, callback) {
var message = "Bonjour, " + name + "!";
callback(message);
}
function displayMessage(message) {
console.log(message);
}
greet("John", displayMessage);
C’est un exemple simple de callback où une fonction est passée en tant qu’argument à une autre fonction et est appelée à un moment spécifié, dans ce cas précisément pour afficher le message.
Les promesses / promises
A prononcer PRO-MA-I-ZE ! 🫣 Par rapport aux callbacks on va avoir une syntaxe plus élégante pour gérer les opérations asynchrones en utilisant des objets qui représentent une valeur qui peut être disponible maintenant, dans le futur ou jamais.
Une instance de la classe Promise
en JavaScript possède plusieurs méthodes qui permettent de gérer les résultats et les erreurs associés à l'opération asynchrone.
var myPromise = new Promise(function(resolve, reject) {
// Logique asynchrone
});
myPromise.then(function(result) {
// Gestion de la réussite
}).catch(function(error) {
// Gestion de l'échec
}).finally(function() {
// Gestion finale
});
then(onFulfilled, onRejected)
: Attache un gestionnaire de réussite (onFulfilled
) et un gestionnaire d'échec (onRejected
) à la Promise. Ces gestionnaires sont appelés lorsque la Promise est résolue avec succès (viaresolve
) ou lorsqu'une erreur se produit (viareject
).catch(onRejected)
: Attache un gestionnaire d'échec (onRejected
) à la Promise. Ce gestionnaire est appelé uniquement en cas d'erreur lors de l'exécution de la Promise.finally(onFinally)
: Attache un gestionnaire (onFinally
) qui est appelé lorsque la Promise est résolue ou rejetée, quel que soit le résultat. Il est souvent utilisé pour effectuer des actions de nettoyage ou de finalisation.
Voici un exemple concret :
function greet(name) {
return new Promise(function(resolve, reject) {
var message = "Bonjour, " + name + "!";
resolve(message);
});
}
function displayMessage(message) {
console.log(message);
}
greet("John")
.then(displayMessage)
.catch(function(error) {
console.error("Une erreur s'est produite : " + error);
});
Enfin, les fonctions asynchrones !
Les fonctions asynchrones, quant à elles, permettent d’écrire du code asynchrone de manière plus synchrone en utilisant les mots-clés async et await. Voici un exemple de fonction asynchrone pour une requête HTTP :
async function effectuerRequete() {
try {
const reponse = await fetch('https://api.exemplemedium.com/test');
// Await spécifie que le programme doit attendre la réponse de la requête
const donnees = await reponse.json();
// Ici qu'il doit attendre la conversion de la réponse en JSON
console.log(donnees);
} catch (erreur) {
console.error('Erreur lors de la requête :', erreur);
}
}
effectuerRequete();
L’utilisation de await
permet donc de suspendre l'exécution de la fonction asynchrone jusqu'à ce que la promesse soit résolue (c'est-à-dire que la requête se termine avec succès) ou rejetée (en cas d'erreur).
En utilisant try/catch
, il est ainsi possible de capturer et gérer les éventuelles erreurs qui se produisent pendant l'exécution de la fonction asynchrone.
Pour finir
Même si JavaScript peut exécuter des tâches asynchrones, il reste globalement un langage qui n’exécute qu’une seule instruction à la fois dans le fil d’exécution principal (thread principal). Les tâches asynchrones sont gérées par le moteur JavaScript, qui utilise des mécanismes sous-jacents tels que les événements, les timers…