Deux choses qui séparent l'amateur du pro : Savoir quand ça va exploser, et savoir attendre sans bloquer la scène. Les erreurs, c'est inévitable. L'asynchrone, c'est la vie réelle du web. Maîtrise-les, ou elles te maîtriseront.
9.1 Gestion des Erreurs - Attraper la Balle avant qu'elle ne Tue
Bloc try...catch...finally - Le Filet de Sécurité
// Sans filet
function décoder(code) {
return JSON.parse(code); // Boom si le code est pourri
}
// Avec filet
function décoderSansExploser(code) {
try {
// Code dangereux
return JSON.parse(code);
} catch (erreur) {
// Ce qui se passe si ça plante
console.error("Code corrompu :", erreur.message);
return null; // On rend quelque chose de sûr
} finally {
// S'exécute TOUJOURS, erreur ou pas
console.log("Tentative de décodage terminée.");
}
}
let message = '{mauvais: json}';
let résultat = décoderSansExploser(message); // Pas de crash
L'Objet Error - Le Cadavre de l'Erreur
try {
throw new Error("C'est foutu."); // Lancer une erreur manuellement
} catch (e) {
console.log(e.name); // "Error"
console.log(e.message); // "C'est foutu."
console.log(e.stack); // La pile d'appels (où ça a merdé)
// L'erreur est un objet comme un autre
e.heure = new Date();
e.niveau = "critique";
console.log(e);
}
Types d'Erreurs Natifs - Connaître l'Ennemi
// SyntaxError : Le code lui-même est mal écrit.
// let 123bad = "test"; // ❌ SyntaxError
// TypeError : Opération sur un type incorrect.
let rien;
// rien.toUpperCase(); // ❌ TypeError: Cannot read properties of undefined
// ReferenceError : Variable qui n'existe pas.
// console.log(fantôme); // ❌ ReferenceError: fantôme is not defined
// RangeError : Valeur hors limites.
// let arr = new Array(-1); // ❌ RangeError: Invalid array length
// URIError : Mauvais encodage d'URL.
// decodeURIComponent('%'); // ❌ URIError: URI malformed
// En pratique
function vérifierCible(cible) {
if (!cible) {
throw new TypeError("Cible manquante.");
}
if (cible.length < 3) {
throw new RangeError("Nom de cible trop court.");
}
// ...
}
try {
vérifierCible("X");
} catch (e) {
if (e instanceof TypeError) {
console.log("Problème de type :", e.message);
} else if (e instanceof RangeError) {
console.log("Problème de limites :", e.message);
}
}
Erreurs Personnalisées - Marquer Ton Territoire
class ErreurSécurité extends Error {
constructor(message, code, ...params) {
super(message, ...params);
this.name = "ErreurSécurité";
this.code = code;
this.date = new Date();
}
}
function accèsZoneRestreinte(niveau) {
if (niveau < 7) {
throw new ErreurSécurité("Niveau d'accès insuffisant.", "E403");
}
return "Accès accordé.";
}
try {
accèsZoneRestreinte(5);
} catch (e) {
if (e instanceof ErreurSécurité) {
console.error(`[${e.code}] ${e.name} : ${e.message} (${e.date})`);
// "[E403] ErreurSécurité : Niveau d'accès insuffisant. (Mon Mar 17...)"
}
}
Bonnes Pratiques - Ne Pas Mourir Idiotement
// 1. TOUJOURS attraper les erreurs des promesses (on y vient)
// 2. Être spécifique dans les catch
try {
// ...
} catch (e) {
if (e instanceof MonErreur) {
// Gérer précisément
} else {
// Relancer pour un autre niveau
throw e;
}
}
// 3. Nettoyer dans finally
let ressource;
try {
ressource = acquérirRessource();
// ... utiliser
} finally {
if (ressource) {
libérerRessource(ressource); // TOUJOURS exécuté
}
}
// 4. Valider tôt, échouer tôt
function traiterDonnées(données) {
if (!données || typeof données !== 'object') {
throw new TypeError("Données invalides.");
}
// Le reste est plus sûr...
}
9.2 Asynchronisme - Attendre Sans Perdre le Fil
Nature Asynchrone de JavaScript - Le Monde Réel
console.log("Début de la surveillance.");
setTimeout(() => {
console.log("Cible en mouvement."); // Ça arrive PLUS TARD
}, 1000);
console.log("Surveillance en cours...");
// Sortie :
// "Début de la surveillance."
// "Surveillance en cours..."
// (1 seconde plus tard) "Cible en mouvement."
// JavaScript ne BLOQUE PAS. Il met en attente et continue.
Callbacks et l'Enfer des Callbacks (Callback Hell)
// Un callback : fonction passée en argument, appelée PLUS TARD.
function observer(cible, callback) {
setTimeout(() => {
callback(`${cible} repérée.`);
}, 500);
}
observer("Alpha", (message) => {
console.log(message);
observer("Beta", (message2) => {
console.log(message2);
observer("Gamma", (message3) => {
console.log(message3);
// Et ainsi de suite... L'ENFER.
// Indentation à l'infini, gestion d'erreur impossible.
});
});
});
Promesses - Une Meilleure Attente
// Une Promesse est un objet qui représente une tâche future.
// Elle peut être : en attente (pending), tenue (fulfilled), ou rompue (rejected).
function observerPromesse(cible) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() > 0.2) { // 80% de chance de succès
resolve(`${cible} localisée avec succès.`);
} else {
reject(new Error(`Perte de contact avec ${cible}.`));
}
}, 500);
});
}
// Utilisation avec .then() et .catch()
observerPromesse("Alpha")
.then(message => {
console.log("Succès :", message);
return observerPromesse("Beta"); // Chaînage
})
.then(message => {
console.log("Succès :", message);
})
.catch(erreur => {
console.error("Échec :", erreur.message);
})
.finally(() => {
console.log("Opération terminée."); // Toujours exécuté
});
Méthodes Utiles des Promesses
// Promise.all : Attendre que TOUTES les promesses soient tenues.
let missions = [
observerPromesse("Cible A"),
observerPromesse("Cible B"),
observerPromesse("Cible C")
];
Promise.all(missions)
.then(résultats => {
console.log("Toutes cibles localisées :", résultats);
})
.catch(erreur => {
// Échoue si UNE SEULE promesse est rompue
console.error("Une mission a échoué :", erreur.message);
});
// Promise.race : La première qui termine (succès ou échec).
Promise.race(missions)
.then(premierRésultat => {
console.log("Première localisation :", premierRésultat);
});
// Promise.allSettled : Attendre que TOUTES soient terminées (succès ou échec).
Promise.allSettled(missions)
.then(résultats => {
résultats.forEach((r, i) => {
if (r.status === 'fulfilled') {
console.log(`Mission ${i} : ${r.value}`);
} else {
console.log(`Mission ${i} échouée : ${r.reason.message}`);
}
});
});
async/await - L'Asynchrone qui a l'Air Synchrone
// `async` transforme une fonction pour qu'elle retourne une Promesse.
// `await` met en pause l'exécution jusqu'à ce qu'une Promesse soit tenue.
async fonction deSurveillance() {
try {
console.log("Lancement de la surveillance...");
const résultat1 = await observerPromesse("Nord"); // Attend ici
console.log(résultat1);
const résultat2 = await observerPromesse("Sud");
console.log(résultat2);
const [résultat3, résultat4] = await Promise.all([
observerPromesse("Est"),
observerPromesse("Ouest")
]);
console.log("Est et Ouest :", résultat3, résultat4);
return "Surveillance complète.";
} catch (erreur) {
console.error("Panne dans la surveillance :", erreur.message);
throw erreur; // Relance l'erreur
}
}
// Appel
deSurveillance()
.then(message => console.log(message))
.catch(e => console.error("Échec global :", e.message));
// ATTENTION : `await` ne marche QUE dans une fonction `async`.
Gestion d'Erreurs avec async/await
// Méthode 1 : try/catch classique (recommandé)
async fonction mission() {
try {
let info = await obtenirInfoSecrète();
let décodé = await décoder(info);
return décodé;
} catch (e) {
console.error("Mission compromise :", e);
return null; // Valeur par défaut
}
}
// Méthode 2 : Attraper chaque promesse individuellement
async fonction missionRobuste() {
let info = await obtenirInfoSecrète().catch(e => {
console.error("Impossible d'obtenir l'info :", e);
return "valeur_par_défaut";
});
let décodé = await décoder(info).catch(e => {
console.error("Décodage échoué :", e);
return "indéchiffrable";
});
return décodé;
}
// Méthode 3 : wrapper utilitaire
function attendreSansPeur(promise) {
return promise
.then(data => ({ data, error: null }))
.catch(error => ({ data: null, error }));
}
async fonction missionSécurisée() {
let { data: info, error: err1 } = await attendreSansPeur(obtenirInfoSecrète());
if (err1) {
// Gérer l'erreur sans try/catch
return "échec_étape_1";
}
let { data: décodé, error: err2 } = await attendreSansPeur(décoder(info));
if (err2) {
return "échec_étape_2";
}
return décodé;
}
Résumé de ce chapitre sombre :
Pour les Erreurs :
try/catch/finally: Ton filet de sécurité. Utilise-le pour le code qui peut exploser.- Types d'erreurs : Connais les différents types pour mieux les traiter.
- Erreurs personnalisées : Crée les tiennes pour des messages et codes clairs.
- Bonnes pratiques : Valide tôt, nettoie toujours, sois spécifique.
Pour l'Asynchrone :
- Callbacks : L'ancienne méthode. Évite l'enfer des imbrications.
- Promesses : L'objet qui représente un futur résultat. Utilise
.then(),.catch(),.finally(). Promise.all/.race/.allSettled: Pour coordonner plusieurs promesses.async/await: La syntaxe moderne qui rend l'asynchrone lisible. Utilisetry/catchavec.
La philosophie :
- Erreurs : Assume qu'elles arriveront. Attrape-les, logue-les, gère-les proprement.
- Asynchrone : Le monde n'attend pas. Apprends à gérer l'attente sans bloquer le reste.
Maîtrise ces deux aspects, et ton code survivra à la nuit.