Vous ĂȘtes-vous dĂ©jĂ demandĂ© comment les navigateurs lisent et exĂ©cutent le code JavaScript? Cela semble mystĂ©rieux, mais dans ce post, vous pouvez avoir une idĂ©e de ce qui se passe sous le capot.
Nous commençons notre voyage dans la langue par une excursion dans le monde merveilleux des moteurs JavaScript.
Ouvrez la console dans Chrome et accédez à l'onglet Sources. Vous verrez plusieurs sections, et l'une des plus intéressantes s'appelle
Call Stack (dans Firefox, vous verrez Call Stack lorsque vous mettez un point d'arrĂȘt dans le code):

Qu'est-ce qu'une pile d'appels? Il semble y avoir beaucoup de choses ici, mĂȘme pour exĂ©cuter quelques lignes de code. En fait, JavaScript n'est pas fourni avec tous les navigateurs. Il existe un grand composant qui compile et interprĂšte notre code JavaScript - c'est un moteur JavaScript. Les plus populaires sont la V8, elle est utilisĂ©e dans Google Chrome et Node.js, SpiderMonkey dans Firefox, JavaScriptCore dans Safari / WebKit.
Les moteurs JavaScript sont aujourd'hui d'excellents exemples de gĂ©nie logiciel, et il sera presque impossible de parler de tous les aspects. Cependant, le travail principal sur l'exĂ©cution de code est effectuĂ© pour nous par seulement quelques composants des moteurs: pile des appels (pile des appels), mĂ©moire globale (mĂ©moire globale) et contexte d'exĂ©cution (contexte d'exĂ©cution). PrĂȘt Ă les rencontrer?
Contenu:
- Moteurs JavaScript et mémoire globale
- Moteurs JavaScript: comment fonctionnent-ils? Contexte d'exécution global et pile d'appels
- JavaScript est un thread unique et d'autres histoires amusantes
- JavaScript asynchrone, file d'attente de rappel et boucle d'événements
- Enfer de rappel et promet ES6
- Création et utilisation de promesses JavaScript
- Gestion des erreurs dans les promesses ES6
- Combinateurs ES6 Promise: Promise.all, Promise.allSettled, Promise.any et autres
- Promesses ES6 et file d'attente de microtĂąches
- Moteurs JavaScript: comment fonctionnent-ils? Evolution asynchrone: des promesses Ă l'async / attente
- Moteurs JavaScript: comment fonctionnent-ils? Résumé
1. Moteurs JavaScript et mémoire globale
J'ai dit que JavaScript est à la fois un langage compilé et interprété. Croyez-le ou non, les moteurs JavaScript compilent réellement vos microsecondes de code avant son exécution.
Une sorte de magie, hein? Cette magie s'appelle JIT (compilation juste Ă temps). C'est Ă lui seul un grand sujet de discussion, mĂȘme les livres ne suffiront pas Ă dĂ©crire le travail de JIT. Mais pour l'instant, nous allons sauter la thĂ©orie et nous concentrer sur la phase d'exĂ©cution, ce qui n'est pas moins intĂ©ressant.
Pour commencer, regardez ce code:
var num = 2; function pow(num) { return num * num; }
Supposons que je vous demande comment ce code est traité dans un navigateur? Que répondez-vous? Vous pouvez dire: «le navigateur lit le code» ou «le navigateur exécute le code». En réalité, tout n'est pas si simple. Tout d'abord, le code n'est pas lu par le navigateur, mais par le moteur.
Le moteur JavaScript lit le code et dÚs qu'il définit la premiÚre ligne, il met quelques liens en
mémoire globale .
La mémoire globale (également appelée tas) est la zone dans laquelle le moteur JavaScript stocke les variables et les déclarations de fonction. Et quand il lit le code ci-dessus, deux classeurs apparaissent dans la mémoire globale:

MĂȘme si l'exemple ne contient qu'une variable et une fonction, imaginez que votre code JavaScript est exĂ©cutĂ© dans un environnement plus grand: dans un navigateur ou dans Node.js. Dans de tels environnements, il existe de nombreuses fonctions et variables prĂ©dĂ©finies appelĂ©es globales. Par consĂ©quent, la mĂ©moire globale contiendra beaucoup plus de donnĂ©es que simplement
num
et
pow
, gardez Ă l'esprit.
Rien ne fonctionne pour le moment. Essayons maintenant d'exécuter notre fonction:
var num = 2; function pow(num) { return num * num; } pow(num);
Que va-t-il se passer? Et quelque chose d'intéressant se produira. Lors de l'appel de la fonction, le moteur JavaScript mettra en évidence deux sections:
- Contexte d'exécution global
- Pile d'appels
Quels sont-ils?
2. Les moteurs JavaScript: comment fonctionnent-ils? Contexte d'exécution global et pile d'appels
Vous avez appris comment le moteur JavaScript lit les variables et les déclarations de fonction. Ils tombent dans la mémoire globale (tas).
Mais maintenant, nous exécutons une fonction JavaScript, et le moteur devrait s'en occuper. Comment? Chaque moteur JavaScript a un
composant clé appelé la pile d'appels .
Il s'agit d'une structure de donnĂ©es empilĂ©e : des Ă©lĂ©ments peuvent y ĂȘtre ajoutĂ©s par le haut, mais ils ne peuvent pas ĂȘtre exclus de la structure tant qu'il y a d'autres Ă©lĂ©ments au-dessus d'eux. Voici comment fonctionnent les fonctions JavaScript. Lors de l'exĂ©cution, ils ne peuvent pas quitter la pile d'appels si une autre fonction y est prĂ©sente. Faites attention Ă cela, car ce concept aide Ă comprendre l'Ă©noncĂ© «JavaScript est un thread unique».
Mais revenons Ă notre exemple.
Lorsqu'une fonction est appelée, le moteur l'envoie à la pile d'appels :

J'aime présenter la pile d'appels comme une pile de jetons Pringles. Nous ne pouvons pas manger de chips du bas de la pile avant d'avoir mangé celles qui sont en haut. Heureusement, notre fonction est synchrone: c'est juste une multiplication qui est rapidement calculée.
Dans le mĂȘme temps, le moteur place le
contexte d'exécution global en mémoire, c'est l'environnement global dans lequel le code JavaScript est exécuté. Voici à quoi ça ressemble:

Imaginez un contexte d'exécution global sous la forme d'une mer dans laquelle les fonctions JavaScript globales flottent comme des poissons. Comme c'est doux! Mais ce n'est que la moitié de l'histoire. Et si notre fonction a des variables imbriquées ou des fonctions internes?
MĂȘme dans le cas simple, comme illustrĂ© ci-dessous, le moteur JavaScript crĂ©e un
contexte d'exécution local :
var num = 2; function pow(num) { var fixed = 89; return num * num; } pow(num);
Notez que j'ai ajouté la variable
fixed
Ă la fonction
pow
. Dans ce cas, le contexte d'exécution local contiendra une section pour
fixed
. Je ne suis pas trÚs bon pour dessiner de petits rectangles à l'intérieur d'autres petits petits rectangles, alors utilisez votre imagination.
Un contexte d'exécution local apparaßtra à cÎté de
pow
, à l'intérieur de la section rectangulaire verte située à l'intérieur du contexte d'exécution global. Imaginez également comment pour chaque fonction imbriquée à l'intérieur de la fonction imbriquée, le moteur crée d'autres contextes d'exécution locaux. Toutes ces sections rectangulaires apparaissent trÚs rapidement! Comme une poupée gigogne!
Revenons Ă l'histoire Ă fil unique. Qu'est-ce que cela signifie?
3. JavaScript est un thread unique et d'autres histoires amusantes
Nous disons que
JavaScript est monothread car une seule pile d'appels gÚre nos fonctions . Permettez-moi de vous rappeler que les fonctions ne peuvent pas quitter la pile d'appels si d'autres fonctions attendent l'exécution.
Ce n'est pas un problÚme si nous travaillons avec du code synchrone. Par exemple, l'addition de deux nombres est synchrone et est calculée en microsecondes. Qu'en est-il des appels réseau et des autres interactions avec le monde extérieur?
Heureusement,
les moteurs JavaScript sont conçus pour fonctionner de maniĂšre asynchrone par dĂ©faut . MĂȘme s'ils ne peuvent exĂ©cuter qu'une seule fonction Ă la fois, des fonctions plus lentes peuvent ĂȘtre exĂ©cutĂ©es par une entitĂ© externe - dans notre cas, il s'agit d'un navigateur. Nous en parlerons ci-dessous.
Dans le mĂȘme temps, vous savez que lorsque le navigateur charge une sorte de code JavaScript, le moteur lit ce code ligne par ligne et effectue les Ă©tapes suivantes:
- Place les variables et les déclarations de fonction dans la mémoire globale (tas).
- Envoie un appel Ă chaque fonction de la pile d'appels.
- Crée un contexte d'exécution global dans lequel les fonctions globales sont exécutées.
- Crée de nombreux petits contextes d'exécution locaux (s'il existe des variables internes ou des fonctions imbriquées).
Vous avez maintenant une compréhension de base des mécanismes de synchronisation qui sous-tendent tous les moteurs JavaScript. Dans le chapitre suivant, nous parlerons du fonctionnement du code asynchrone en JavaScript et pourquoi il fonctionne de cette façon.
4. JavaScript asynchrone, file d'attente de rappel et boucle d'événement
Grùce à la mémoire globale, au contexte d'exécution et à la pile d'appels, le code JavaScript synchrone est exécuté dans nos navigateurs. Mais nous avons oublié quelque chose. Que se passe-t-il si vous devez exécuter une sorte de fonction asynchrone?
Par fonction asynchrone, je veux dire chaque interaction avec le monde extérieur, qui peut prendre un certain temps. L'appel de l'API REST ou du temporisateur est asynchrone, car leur exécution peut prendre quelques secondes. Grùce aux éléments disponibles dans le moteur, nous pouvons traiter de telles fonctions sans bloquer la pile d'appels et le navigateur. N'oubliez pas, la pile d'appels ne peut exécuter qu'une seule fonction à la fois, et
mĂȘme une fonction de blocage peut littĂ©ralement arrĂȘter le navigateur . Heureusement, les moteurs JavaScript sont intelligents et, avec un peu d'aide du navigateur, ils peuvent trier les choses.
Lorsque nous exécutons une fonction asynchrone, le navigateur la prend et l'exécute pour nous. Prenez un minuteur comme celui-ci:
setTimeout(callback, 10000); function callback(){ console.log('hello timer!'); }
Je suis sĂ»r que mĂȘme si vous avez dĂ©jĂ vu
setTimeout
centaines de fois, vous ne savez peut-ĂȘtre pas que
cette fonction n'est pas intégrée à JavaScript . Ainsi, lorsque JavaScript est apparu, il n'y avait pas de fonction
setTimeout
. En fait, il fait partie des soi-disant API de navigateur, une collection d'outils pratiques que le navigateur nous fournit. Magnifique! Mais qu'est-ce que cela signifie dans la pratique? Puisque
setTimeout
fait rĂ©fĂ©rence Ă l'API du navigateur, cette fonction est exĂ©cutĂ©e par le navigateur lui-mĂȘme (pendant un moment, elle apparaĂźt dans la pile des appels, mais est immĂ©diatement supprimĂ©e de lĂ ).
AprĂšs 10 secondes, le navigateur prend la fonction de rappel que nous lui avons transmise et la place dans la
file d'attente de rappel . Pour le moment, deux autres sections rectangulaires sont apparues dans le moteur JavaScript. Jetez un oeil Ă ce code:
var num = 2; function pow(num) { return num * num; } pow(num); setTimeout(callback, 10000); function callback(){ console.log('hello timer!'); }
Maintenant, notre schéma ressemble à ceci:

setTimeout
est exĂ©cutĂ© dans le contexte du navigateur. AprĂšs 10 secondes, la minuterie dĂ©marre et la fonction de rappel est prĂȘte Ă ĂȘtre exĂ©cutĂ©e. Mais d'abord, il doit passer par la file d'attente de rappel. Il s'agit d'une structure de donnĂ©es sous la forme d'une file d'attente et, comme son nom l'indique, est une file d'attente de fonctions ordonnĂ©e.
Chaque fonction asynchrone doit passer par une file d'attente de rappel avant d'entrer dans la pile d'appels. Mais qui envoie ensuite les fonctions? Cela fait un composant appelé
une boucle d'événements .
Jusqu'à présent, la boucle d'événement ne traite que d'une chose: elle vérifie si la pile d'appels est vide. S'il y a une fonction dans la file d'attente de rappel et si la pile d'appels est libre, il est temps d'envoyer un rappel à la pile d'appels.
AprÚs cela, la fonction est considérée comme exécutée. Voici le schéma général de traitement du code asynchrone et synchrone avec le moteur JavaScript:

Disons que
callback()
est prĂȘt Ă ĂȘtre exĂ©cutĂ©. Lorsque
pow()
la pile d'appels est libérée et la boucle d'événements lui envoie callback()
. Et c'est tout! Bien que j'aie un peu simplifié les choses, si vous comprenez le schéma ci-dessus, vous pouvez comprendre tout le JavaScript.
N'oubliez pas:
les API basées sur le navigateur, les files d'attente de rappel et les boucles d'événements sont les piliers du JavaScript asynchrone .
Et si vous ĂȘtes intĂ©ressĂ©, vous pouvez regarder la curieuse vidĂ©o «What the diable is the event loop anyway» de Philip Roberts. C'est l'une des meilleures explications de la boucle d'Ă©vĂ©nements.
Mais nous n'avons pas encore fini avec le thĂšme JavaScript asynchrone. Dans les chapitres suivants, nous examinerons les promesses de l'ES6.
5. Enfer de rappel et promesses d'ES6
Les fonctions de rappel sont utilisées partout en JavaScript, aussi bien en code synchrone qu'en code asynchrone. Considérez cette méthode:
function mapper(element){ return element * 2; } [1, 2, 3, 4, 5].map(mapper);
mapper
est une fonction de rappel qui est passée à l'intérieur de la
map
. Le code ci-dessus est synchrone. Considérez maintenant cet intervalle:
function runMeEvery(){ console.log('Ran!'); } setInterval(runMeEvery, 5000);
Ce code est asynchrone, car à l'intérieur de
setInterval
nous transmettons le rappel runMeEvery. Les rappels sont utilisés dans JavaScript, donc depuis des années, nous avons un problÚme appelé «enfer de rappel» - «enfer de rappel».
Le terme
Hell de rappel en JavaScript est appliqué au "style" de programmation dans lequel les rappels sont intégrés dans d'autres rappels qui sont intégrés dans d'autres rappels ... En raison de la nature asynchrone, les programmeurs JavaScript sont depuis longtemps tombés dans ce piÚge.
Pour ĂȘtre honnĂȘte, je n'ai jamais créé de grandes pyramides de rappels. Peut-ĂȘtre parce que j'apprĂ©cie le code lisible et que j'essaie toujours de m'en tenir Ă ses principes. Si vous frappez l'enfer de rappel, cela signifie que votre fonction en fait trop.
Je ne parlerai pas en dĂ©tail de l'enfer de rappel, si vous ĂȘtes intĂ©ressĂ©, alors allez sur
callbackhell.com , oĂč ce problĂšme a Ă©tĂ© Ă©tudiĂ© en dĂ©tail et diffĂ©rentes solutions ont Ă©tĂ© proposĂ©es. Et nous parlerons des
promesses ES6 . Il s'agit d'un module complémentaire JavaScript conçu pour résoudre le problÚme de rappel de l'enfer. Mais quelles sont les promesses?
Une promesse JavaScript est une représentation d'un événement futur . Une promesse peut se terminer avec succÚs, ou dans un jargon de programmeurs, une promesse sera «résolue» (résolue). Mais si la promesse se termine par une erreur, alors nous disons qu'elle est à l'état rejeté. Les promesses ont également un état par défaut: chaque nouvelle promesse commence dans un état en attente. Puis-je créer ma propre promesse? Oui Nous en parlerons dans le chapitre suivant.
6. Créer et travailler avec des promesses JavaScript
Pour créer une nouvelle promesse, vous devez appeler le constructeur en lui passant une fonction de rappel. Il ne peut prendre que deux paramÚtres:
resolve
et
reject
. Créons une nouvelle promesse qui sera résolue en 5 secondes (vous pouvez tester les exemples dans la console du navigateur):
const myPromise = new Promise(function(resolve){ setTimeout(function(){ resolve() }, 5000) });
Comme vous pouvez le voir, la
resolve
est une fonction que nous appelons pour que la promesse se termine avec succĂšs. Et le
reject
créera une promesse rejetée:
const myPromise = new Promise(function(resolve, reject){ setTimeout(function(){ reject() }, 5000) });
Notez que vous pouvez ignorer le
reject
car il s'agit du deuxiĂšme paramĂštre. Mais si vous avez l'intention d'utiliser le
reject
, vous
ne pouvez pas ignorer la resolve
. Autrement dit, le code suivant ne fonctionnera pas et se terminera par une promesse autorisée:
Les promesses ne semblent pas si utiles en ce moment, non? Ces exemples n'affichent rien pour l'utilisateur. Ajoutons quelque chose. Et les promesses autorisées et rejetées peuvent renvoyer des données. Par exemple:
const myPromise = new Promise(function(resolve) { resolve([{ name: "Chris" }]); });
Mais nous ne voyons toujours rien.
Pour extraire des données d'une promesse, vous devez associer la promesse à la méthode then
. Il prend un rappel (quelle ironie!), Qui reçoit les données actuelles:
const myPromise = new Promise(function(resolve, reject) { resolve([{ name: "Chris" }]); }); myPromise.then(function(data) { console.log(data); });
En tant que développeur JavaScript et consommateur de code d'autrui, vous interagissez principalement avec des promesses externes. Les créateurs de bibliothÚque enveloppent le plus souvent le code hérité dans un constructeur Promise, comme ceci:
const shinyNewUtil = new Promise(function(resolve, reject) {
Et si nécessaire, nous pouvons également créer et résoudre une promesse en appelant
Promise.resolve()
:
Promise.resolve({ msg: 'Resolve!'}) .then(msg => console.log(msg));
Alors, permettez-moi de vous rappeler: les promesses JavaScript sont un signet pour un Ă©vĂ©nement qui se produira Ă l'avenir. Un Ă©vĂ©nement commence dans l'Ă©tat «en attente d'une dĂ©cision» et peut ĂȘtre rĂ©ussi (autorisĂ©, exĂ©cutĂ©) ou Ă©chouĂ© (rejetĂ©). Une promesse peut renvoyer des donnĂ©es qui peuvent ĂȘtre rĂ©cupĂ©rĂ©es en les joignant
then
. Dans le chapitre suivant, nous verrons comment traiter les erreurs provenant des promesses.
7. Gestion des erreurs dans les promesses ES6
La gestion des erreurs en JavaScript a toujours été facile, du moins en code synchrone. Jetez un oeil à un exemple:
function makeAnError() { throw Error("Sorry mate!"); } try { makeAnError(); } catch (error) { console.log("Catching the error! " + error); }
Le résultat sera:
Catching the error! Error: Sorry mate!
Comme prévu, l'erreur est tombée dans le
catch
. Essayez maintenant la fonction asynchrone:
function makeAnError() { throw Error("Sorry mate!"); } try { setTimeout(makeAnError, 5000); } catch (error) { console.log("Catching the error! " + error); }
Ce code est asynchrone en raison de
setTimeout
. Que se passera-t-il si nous l'exécutons?
throw Error("Sorry mate!"); ^ Error: Sorry mate! at Timeout.makeAnError [as _onTimeout] (/home/valentino/Code/piccolo-javascript/async.js:2:9)
Maintenant, le résultat est différent. L'erreur n'a pas été détectée par le
catch
, mais a remonté librement la pile. La raison en est que
try/catch
ne fonctionne qu'avec du code synchrone. Si vous voulez en savoir plus, ce problÚme est abordé en détail
ici .
Heureusement, avec des promesses, nous pouvons gérer les erreurs asynchrones comme si elles étaient synchrones. Dans le dernier chapitre, j'ai dit que l'appel au
reject
conduit Ă un rejet de la promesse:
const myPromise = new Promise(function(resolve, reject) { reject('Errored, sorry!'); });
Dans ce cas, nous pouvons gérer les erreurs en utilisant le gestionnaire de
catch
en tirant (Ă nouveau) un rappel:
const myPromise = new Promise(function(resolve, reject) { reject('Errored, sorry!'); }); myPromise.catch(err => console.log(err));
De plus, pour créer et rejeter une promesse au bon endroit, vous pouvez appeler
Promise.reject()
:
Promise.reject({msg: 'Rejected!'}).catch(err => console.log(err));
Permettez-moi de vous rappeler: le gestionnaire
then
est exécuté lorsque la promesse est exécutée, et le gestionnaire
catch
est exécuté pour les promesses rejetées. Mais ce n'est pas la fin de l'histoire. Ci-dessous, nous verrons comment
async/await
fonctionne trĂšs bien avec
try/catch
.
8. Combinateurs de promesses ES6: Promise.all, Promise.allSettled, Promise.any et autres
Les promesses ne sont pas conçues pour fonctionner seules. L'API Promise propose un certain nombre de méthodes pour
combiner des promesses . L'un des plus utiles
est Promise.all , il prend un tableau de promesses et renvoie une promesse. Le seul problÚme est que Promise.all est rejeté si au moins une promesse du tableau est rejetée.
Promise.race autorise ou rejette dÚs que l'une des promesses du tableau reçoit le statut correspondant.
Dans les versions plus récentes de V8, deux nouveaux combinateurs seront également introduits:
Promise.allSettled
et
Promise.any
.
Promise.any est encore à un stade précoce de la fonctionnalité proposée, au moment de la rédaction de cet article, il n'est pas pris en charge. Cependant, en théorie, il pourra signaler si une promesse a été exécutée. La différence avec
Promise.race
est que
Promise.any n'est pas rejetĂ©, mĂȘme si l'une des promesses est rejetĂ©e .
Promise.allSettled
encore plus intĂ©ressant. Il prend Ă©galement un Ă©ventail de promesses, mais ne «raccourcit» pas si l'une des promesses est rejetĂ©e. Il est utile lorsque vous devez vĂ©rifier si toutes les promesses d'un tableau sont passĂ©es Ă un certain stade, indĂ©pendamment de la prĂ©sence de promesses rejetĂ©es. Cela peut ĂȘtre considĂ©rĂ© comme l'opposĂ© de
Promise.all
.
9. ES6 Promesses et la file d'attente des microtĂąches
Si vous vous souvenez du chapitre précédent, chaque fonction de rappel asynchrone en JavaScript se trouve dans la file d'attente de rappel avant de toucher la pile d'appels. Mais les fonctions de rappel passées à Promise ont un sort différent: elles sont traitées par la file d'attente des microtùches, plutÎt que par la file d'attente des tùches.
Et ici, vous devez ĂȘtre prudent: la
file d'attente des microtĂąches prĂ©cĂšde la file d'attente des appels . Les rappels Ă partir de la file d'attente des microtĂąches ont prioritĂ© lorsque la boucle d'Ă©vĂ©nements vĂ©rifie si de nouveaux rappels sont prĂȘts Ă passer sur la pile d'appels.
Cette mécanique est décrite plus en détail par Jake Archibald dans
TĂąches, microtĂąches, files d'attente et plannings , grande lecture.
10. Moteurs JavaScript: comment fonctionnent-ils? Evolution asynchrone: des promesses Ă l'async / attente
JavaScript évolue rapidement et nous obtenons constamment des améliorations chaque année. Les promesses ressemblaient à une finale, mais
avec ECMAScript 2017 (ES8) une nouvelle syntaxe est apparue: async/await
.
async/await
n'est qu'une amélioration stylistique que nous appelons le sucre syntaxique.
async/await
ne modifie en aucune façon JavaScript (n'oubliez pas que la langue doit ĂȘtre rĂ©trocompatible avec les navigateurs plus anciens et ne doit pas casser le code existant). Ceci est juste une nouvelle façon d'Ă©crire du code asynchrone basĂ© sur des promesses. Prenons un exemple. Ci-dessus, nous avons dĂ©jĂ enregistrĂ© la promesse dans le correspondant
then
:
const myPromise = new Promise(function(resolve, reject) { resolve([{ name: "Chris" }]); }); myPromise.then((data) => console.log(data))
Maintenant,
avec async/await
nous pouvons traiter le code asynchrone de sorte que pour le lecteur de notre liste, le code soit synchrone . Au lieu d'utiliser
then
nous pouvons encapsuler la promesse dans une fonction appelée
async
, puis nous
await
résultat:
const myPromise = new Promise(function(resolve, reject) { resolve([{ name: "Chris" }]); }); async function getData() { const data = await myPromise; console.log(data); } getData();
Ăa a l'air bien, non? C'est drĂŽle qu'une fonction asynchrone retourne toujours une promesse, et personne ne peut l'empĂȘcher de faire ceci:
async function getData() { const data = await myPromise; return data; } getData().then(data => console.log(data));
Et les erreurs? L'un des avantages de
async/await
est que cette construction peut nous permettre d'utiliser
try/catch
. Lisez l'
introduction Ă la gestion des erreurs dans les fonctions asynchrones et leurs tests .
Reprenons la promesse, dans laquelle nous gérons les erreurs avec le gestionnaire de
catch
:
const myPromise = new Promise(function(resolve, reject) { reject('Errored, sorry!'); }); myPromise.catch(err => console.log(err));
Avec les fonctions asynchrones, nous pouvons refactoriser comme ceci:
async function getData() { try { const data = await myPromise; console.log(data);
Cependant, tout le monde n'est pas passé à ce style.
try/catch
peut compliquer votre code. Il y a encore une chose à considérer. Voyez comment une erreur se produit dans ce bloc
try
dans ce code:
async function getData() { try { if (true) { throw Error("Catch me if you can"); } } catch (err) { console.log(err.message); } } getData() .then(() => console.log("I will run no matter what!")) .catch(() => console.log("Catching err"));
Qu'en est-il des deux lignes affichées dans la console? N'oubliez pas que
try/catch
est une construction synchrone et que notre fonction asynchrone génÚre une promesse . Ils suivent deux chemins différents, comme les trains. ! ,
throw
,
catch
getData()
. , «Catch me if you can», «I will run no matter what!».
,
throw
then
. , ,
Promise.reject()
:
async function getData() { try { if (true) { return Promise.reject("Catch me if you can"); } } catch (err) { console.log(err.message); } } Now the error will be handled as expected: getData() .then(() => console.log("I will NOT run no matter what!")) .catch(() => console.log("Catching err")); "Catching err"
async/await
JavaScript. .
, JS-
async/await
. . ,
async/await
â .
11. JavaScript-: ?
JavaScript â , , . JS-: V8, Google Chrome Node.js; SpiderMonkey, Firefox; JavaScriptCore, Safari.
JavaScript- «» : , , , . , .
JavaScript- , . JavaScript: , - , (, ) .
ECMAScript 2015 . â , . . 2017-
async/await
: , , .