Le flux de contrôle correspond à l'ordre dans lequel l'interpréteur JavaScript s'exécute. . Si un script n'inclut pas d'instructions qui modifient son flux, exécutées du début à la fin, une ligne à la fois. Les structures de contrôle sont utilisées pour déterminer si un ensemble d'instructions est exécuté ou non d'un ensemble défini de critères, d'exécuter un ensemble d'instructions de façon répétée ou d'interrompre une séquence d'instructions.
Instructions conditionnelles
Les instructions conditionnelles déterminent
si le code doit être exécuté en fonction d'un ou
d'autres conditions. Une instruction conditionnelle exécute le code qu'elle contient si le
la condition (ou l'ensemble de conditions) associée prend la valeur true
. Dans le cas contraire,
est ignoré.
if
... else
else
Une instruction if
évalue une condition à l'intérieur des parenthèses correspondantes qui
suivre. Si la condition entre parenthèses renvoie true
, la
ou relevé de blocage
qui suit les parenthèses correspondantes est exécuté:
if ( true ) console.log( "True." );
> "True."
if ( true ) {
const myString = "True.";
console.log( myString );
}
> "True."
Si la condition entre parenthèses est évaluée à false
, l'instruction qui
suit, elle est ignorée:
if ( false ) console.log( "True." );
Un mot clé else
juste après une instruction if
et ses
exécutée de manière conditionnelle spécifie l'instruction à exécuter si la
La condition if
renvoie la valeur false
:
if ( false ) console.log( "True." )''
else console.log( "False" );
> "False."
Pour enchaîner plusieurs instructions if
, vous pouvez définir
Instruction exécutée de manière conditionnelle après else
une autre instruction if
:
const myCondition = 2;
if ( myCondition === 5 ) console.log( "Five." );
else if ( myCondition === 2 ) console.log( "Two." );
Nous vous recommandons vivement d'utiliser la syntaxe d'instruction de bloc suivant les instructions conditionnelles pour
améliorer la lisibilité, mais les clauses else if
font souvent exception à cette règle:
if ( myCondition === 5 ) {
console.log( "Five." );
} else if ( myCondition === 3 ) {
console.log( "Three" );
} else {
console.log( "Neither five nor three." );
}
> "Neither five nor three."
Opérateur ternaire
if
exécute une instruction de manière conditionnelle. L'opérateur ternaire (plus précisément,
mais moins communément appelé opérateur conditionnel ternaire), est utilisé sous forme abrégée.
pour exécuter une expression de manière conditionnelle. Comme son nom l'indique,
est le seul opérateur JavaScript qui utilise trois opérandes:
- Une condition à évaluer, suivie d'un point d'interrogation (
?
). - Expression à exécuter si la condition renvoie
true
, suivie d'une deux-points (:
). - Expression à exécuter si la condition renvoie
false
.
Cette méthode est fréquemment utilisée pour définir ou transmettre une valeur de manière conditionnelle:
const myFirstResult = true ? "First value." : "Second value.";
const mySecondResult = false ? "First value." : "Second value.";
myFirstResult;
> "First value."
mySecondResult;
> "Second value."
switch
... case
Utilisez l'instruction switch
pour comparer la valeur d'une expression à une liste de
les valeurs potentielles définies à l'aide d'un ou de plusieurs mots clés case
. Cette syntaxe est
inhabituelle car elle provient de certaines des premières
décisions de conception de JavaScript.
La syntaxe switch
...case
utilise le mot clé switch
, suivi d'une expression pour
être évaluées entre parenthèses, suivies d'une paire d'accolades identiques.
Le corps de switch
peut contenir case
mots clés, généralement un ou plusieurs,
suivie d'une expression ou d'une valeur, puis du signe deux-points (:
).
Lorsque l'interpréteur atteint un case
dont la valeur correspond à l'expression en cours
évaluée entre parenthèses après le mot clé switch
, il exécute toutes les
qui suivent cette clause case
:
switch ( 2 + 2 === 4 ) {
case false:
console.log( "False." );
case true:
console.log( "True." );
}
> "True."
Toutes les instructions qui suivent l'instruction case
correspondante sont exécutées, même si elles sont
incluse dans une instruction de bloc.
switch ( 2 + 2 === 4 ) {
case false:
console.log( "False." );
case true:
let myVariable = "True.";
console.log( myVariable );
}
> "True."
L'un des pièges liés à l'utilisation de switch…case
est qu'après la détection d'une correspondance,
L'interpréteur JavaScript exécute n'importe quelle instruction qui suit l'instruction case
correspondante,
même celles incluses dans d'autres clauses case
. C'est ce qu'on appelle
la « tombée » vers
case
suivant:
switch ( 2 + 2 === 7 ) {
case false:
console.log( "False." );
case true:
console.log( "True." );
}
> "False."
> "True."
Pour éviter toute interruption, terminez chaque cas par le mot clé break
, qui
arrête immédiatement l'évaluation du corps switch
:
switch ( 2 + 2 === 7 ) {
case false:
console.log( "False." );
break;
case true:
console.log( "True." );
break;
}
> "False."
Si aucune case
ne correspond à la valeur conditionnelle, switch
sélectionne l'default
s'il en existe une:
switch ( 20 ) {
case 5:
console.log( "The value was five." );
break;
case 10:
console.log( "The value was ten." );
break;
default:
console.log( "The value was something unexpected." );
}
> "The value was something unexpected."
Toutefois, la chute s'applique également à default
, ce qui peut entraîner
des résultats inattendus. Pour résoudre ce problème, terminez votre instruction default
par break
.
ou le placer en dernier dans la liste des cas.
switch ( 20 ) {
default:
console.log( "The value was something unexpected." );
case 10:
console.log( "The value was ten." );
break;
case 5:
console.log( "The value was five." );
break;
}
> The value was something unexpected.
> The value was ten.
Étant donné que les clauses case
ne nécessitent pas
instruction de bloc pour le regroupement
plusieurs instructions, les clauses case
et default
ne créent pas
champ d'application lexical:
let myVariable;
switch ( true ) {
case true:
let myVariable = "True.";
break;
default:
let myVariable = "False.";
break;
}
> Uncaught SyntaxError: redeclaration of let myVariable
Pour gérer le champ d'application, utilisez des instructions de blocage:
let myVariable;
switch ( true ) {
case true: {
let myVariable = "True.";
break;
}
default: {
let myVariable = "False.";
break;
}
}
Boucles et itérations
Les boucles vous permettent de répéter un ensemble d'instructions aussi longtemps qu'une condition est remplie. jusqu'à ce qu'une condition soit remplie. Utilisez des boucles pour exécuter un ensemble d'instructions un certain nombre de fois, jusqu'à l'obtention d'un résultat spécifique ou jusqu'à ce que l'interpréteur atteint la fin d'une structure de données itérable (par exemple, l'élément final dans un tableau, une carte ou un ensemble, la propriété finale d'un objet ou le dernier caractère de une chaîne).
Les boucles interrompent la lecture du haut vers le bas le flux d'exécution d'un script par itération sur un ensemble d'instructions, jusqu'à ce qu'une ou plusieurs conditions soient remplies ou ne soient plus est satisfaite, selon la syntaxe utilisée pour créer la boucle. Une fois la boucle terminée, l'exécution se poursuit avec les déclarations qui la suivent. Dans l'exemple suivant, les instructions du corps de la boucle sont exécutées trois fois avant que l'interprète passe à autre chose:
let iterationCount = 0;
console.log( "Pre-loop." );
while( iterationCount < 3 ) {
iterationCount++;
console.log( "Loop iteration." );
}
console.log( "Continuing on." );
> "Pre-loop."
> "Loop iteration."
> "Loop iteration."
> "Loop iteration."
> "Continuing on."
Si les conditions ne peuvent pas être remplies lors de l'exécution de la boucle, celle-ci se poursuit indéfiniment. Ces boucles infinies sont un piège de programmation courant qui peut le thread d'exécution principal de suspendre indéfiniment l'accès, voire de faire planter un onglet du navigateur.
L'exemple suivant s'exécute tant que la valeur booléenne true
reste
true
Comme les valeurs booléennes sont immuables,
cela crée une boucle infinie.
console.log( "Pre-loop." );
while( true ) {
console.log( "Loop iteration." );
}
> "Pre-loop."
> "Loop iteration."
> "Loop iteration."
> "Loop iteration."
> "Loop iteration."
> "Loop iteration."
…
Évitez de laisser des boucles infinies dans votre code de production. Si vous créez accidentellement pendant le développement, vous pouvez le résoudre en fermant l'onglet de navigateur qu'il s'exécute en mettant à jour votre code de sorte que la boucle n'est plus infinie et en rouvrant .
while
Une boucle while
est créée à l'aide du mot clé while
suivi d'une paire de
parenthèses correspondantes contenant une condition à évaluer. Si les valeurs
prend initialement la valeur true
, l'instruction (ou
instruction en bloc) qui suit
ces parenthèses est exécutée. Sinon, la boucle ne s'exécute jamais. Après chaque
la condition est réévaluée. Si elle est toujours true
, la boucle
se répète.
let iterationCount = 0;
while( iterationCount < 3 ) {
iterationCount++;
console.log( `Loop ${ iterationCount }.` );
}
> "Loop 1."
> "Loop 2."
Si l'interpréteur trouve une instruction continue
dans une boucle while
, il arrête cette
l'itération, réévalue la condition et poursuit la boucle si possible:
let iterationCount = 0;
while( iterationCount <= 5 ) {
iterationCount++;
if( iterationCount === 3 ) {
continue;
}
console.log( `Loop ${ iterationCount }.` );
}
console.log( "Loop ended." );
> "Loop 1."
> "Loop 2."
> "Loop 4."
> "Loop 5."
> "Loop ended."
Si l'interpréteur trouve une instruction break
dans une boucle while
, cette itération
s'arrête et que la condition n'est pas réévaluée, ce qui permet à l'interprète de continuer:
let iterationCount = 1;
while( iterationCount <= 5 ) {
if( iterationCount === 3 ) {
console.log(`Iteration skipped.``);`
break;
}
console.log( `Loop ${ iterationCount }.` );
iterationCount++;
}
console.log( "Loop ended." );
> "Loop 1."
> "Loop 2."
> "Iteration skipped.
> "Loop ended."
Vous pouvez utiliser while
pour itérer un nombre spécifié de fois, comme illustré dans
exemple précédent, mais le cas d'utilisation le plus courant de while
est une boucle de
longueur indéterminée:
let randomize = () => Math.floor( Math.random() * 10 );
let randomNum = randomize();
while( randomNum !== 3 ){
console.log( `The number is not ${ randomNum }.` );
randomNum = randomize();
}
console.log( `The correct number, ${ randomNum }, was found.` );
> "The number is not 0."
> "The number is not 6."
> "The number is not 1."
> "The number is not 8."
> "The correct number, 3, was found."
do
... while
do
...while
est une variante de la boucle while
dans laquelle l'instruction conditionnelle
l'évaluation a lieu à la fin de chaque itération de la boucle. Cela signifie que
le corps de la boucle est toujours exécuté au moins une fois.
Pour créer une boucle do
...while
, utilisez le mot clé do
suivi de l'instruction.
(ou relevé de blocage) pour être
à chaque itération de la boucle. Immédiatement après cette
déclaration, ajoutez
while
et des parenthèses correspondantes contenant la condition à évaluer. Quand ?
si cette condition ne renvoie plus la valeur true
, la boucle se termine.
let iterationCount = 1;
do {
console.log( `Loop ${ iterationCount }.` );
iterationCount++;
} while ( iterationCount < 3 );
> "Loop 1."
> "Loop 2."
> "Loop 3."
Comme pour une boucle while
, le cas d'utilisation le plus courant pour do
... while
est une boucle de
longueur indéterminée:
let randomNum;
do {
randomNum = ( () => Math.floor( Math.random() * 10 ) )();
console.log( `Is the number ${ randomNum }?` );
} while ( randomNum !== 3 );
console.log( `Yes, ${ randomNum } was the correct number.` );
> "Is the number 9?"
> "Is the number 2?"
> "Is the number 8?"
> "Is the number 2?"
> "Is the number 3?"
> "Yes, 3 was the correct number."
for
Utilisez des boucles for
pour itérer sur une quantité connue. Dans les anciens codebases, il s'agissait
fréquemment utilisé pour itérer
les éléments d'un tableau.
Pour créer une boucle for
, utilisez le mot clé for
, suivi d'une paire de parenthèses.
qui accepte les trois expressions suivantes dans l'ordre et séparées par
Points-virgules:
- Expression à évaluer au début de la boucle
- Une condition qui détermine si la boucle doit se poursuivre
- Expression à exécuter à la fin de chaque boucle
Après ces parenthèses, ajoutez l’instruction (généralement une instruction de blocage). exécutées pendant la boucle.
for( let i = 0; i < 3; i++ ) {
console.log( "This loop will run three times.")
}
La première expression initialise une variable qui agit comme un compteur. Ce
est évaluée une fois, avant la première itération de la boucle. Vous pouvez
initialisez cette variable en utilisant let
(ou var
, par le passé), comme n'importe quelle autre
variable, et son champ d'application correspond au corps de la boucle. Ces variables peuvent avoir
un identifiant valide, mais ils sont souvent appelés i
pour "itération" ou "index".
Cela semble contredire
Bonnes pratiques concernant les noms d'identifiants prévisibles
mais la convention est suffisamment bien établie pour être claire pour les autres développeurs de
en un coup d'œil. Comme les collections indexées sont indexées à zéro,
ces variables ont presque toujours une valeur initiale de 0
.
Comme pour d'autres formes de boucle, la condition est une expression qui détermine
si la boucle doit être exécutée. Elle sert le plus souvent à définir une valeur
lié au compteur d'itérations. L'interpréteur évalue la condition avant
exécute la boucle for
pour la première fois.Si la condition n'est pas initialement
prend la valeur true
, le corps de la boucle n'est pas exécuté.
L'expression finale est exécutée à la fin de chaque itération dans la boucle. Il est généralement utilisé pour incrémenter l’identifiant d’une unité.
Le plus souvent, vous verrez des itérations for
dans les tableaux dans des
codebases. Dans ce cas, la condition spécifiée pour la poursuite de la boucle est une
nombre d'itérations inférieur ou égal à la longueur du tableau itéré
à travers. La variable utilisée pour suivre le nombre actuel d'itérations sert à rechercher
la valeur associée à cet index dans le tableau, ce qui permet à chaque élément
le tableau sur lequel agir dans l'ordre:
var myArray = [ true, false, true ];
for( let i = 0; i <= myArray.length; i++ ) {
console.log( myArray[ i ] );
}
> true
> false
> true
Cette approche a cessé d'être utilisée au profit d'approches plus modernes de une boucle dans des structures de données itérables.
for
[...] of
[...]
Utilisez les boucles for
...of
... pour itérer les valeurs stockées dans une
structure de données itérable, comme un tableau, un ensemble ou une carte.
Une boucle for
...of
... utilise le mot clé for
, suivi d'une paire de parenthèses.
contenant une variable, suivie de of
, puis de la structure de données en cours d'itération.
terminé. La variable peut être une déclaration effectuée ici à l'aide de let
, const
ou
var
, une variable déclarée précédemment dans le champ d'application actuel, un objet
ou une instance de
destructuration.
Elle contient la valeur de l'élément qui correspond à l'itération actuelle.
de la boucle.
const myIterable = [ true, false, true ];
for( const myElement of myIterable ) {
console.log( myElement );
}
> true
> false
> true
Dans cet exemple, l'utilisation de const
pour myElement
fonctionne même si myElement
est
à une nouvelle valeur à chaque itération de la boucle. En effet, les variables
déclarés avec let
ou const
sont limités à l'instruction de bloc dans la
en boucle. La variable est initialisée au début de chaque itération et supprimée à
la fin de cette itération.
for
... in
...
Utilisez les boucles for
...in
... pour itérer les propriétés énumérables d'un objet.
y compris les propriétés héritées énumérables. Comme pour une boucle for
...of
..., une
La boucle for
...in
... utilise le mot clé for
, suivi d'une paire de parenthèses.
contenant une variable contenant la valeur de la clé de propriété correspondant
avec l'itération actuelle de la boucle. Cette variable est suivie du
in
, puis sur l'objet de l'itération:
const myObject = { "myProperty" : true, "mySecondProperty" : false };
for( const myKey in myObject ) {
console.log( myKey );
}
> "myProperty"
> "mySecondProperty"
Là encore, même si la valeur de myKey
change à chaque itération de la boucle,
vous pouvez utiliser const
sans erreur, car la variable est effectivement supprimée.
à la fin de chaque itération, puis recréés au début.
La valeur associée à chaque clé de propriété n'est pas directement disponible pour
for
...in
... syntaxe. Cependant, comme la boucle a accès à une clé de propriété
chaque itération, vous pouvez utiliser cette clé pour « rechercher » sa valeur:
const myObject = { "myProperty" : true, "mySecondProperty" : false };
for( const myKey in myObject ) {
const myValue = myObject[ myKey ];
console.log( `${ myKey } : ${ myValue }` );
}
> "myProperty : true"
> "mySecondProperty : false"
Les propriétés héritées des constructeurs intégrés ne peuvent pas être énumérées, ce qui signifie que
for
...in
... n'effectue pas d'itération des propriétés héritées de la Object
.
d'un constructeur. Cependant, toute propriété énumérable dans la classe
chaîne de prototype sont inclus:
const myPrototype = { "protoProperty" : true };
const myObject = Object.create( myPrototype, {
myProperty: {
value: true,
enumerable: true
}
});
for ( const myKey in myObject ) {
const myValue = myObject[ myKey ];
console.log( `${ myKey } : ${ myValue }` );
}
> "myProperty : true"
> "protoProperty : true"
JavaScript fournit des méthodes intégrées pour déterminer si une propriété est un
propriété directe de l'objet plutôt qu'une propriété sur le prototype de l'objet
chaîne: le modèle moderne
Object.hasOwn()
et les anciennes méthodes Object.prototype.hasOwnProperty()
. Ces
évaluent si une propriété spécifiée est héritée (ou non déclarée),
en renvoyant true
uniquement pour les propriétés immédiates d'un objet spécifié:
const myPrototype = { "protoProperty" : true };
const myObject = Object.create( myPrototype, {
myProperty: {
value: true,
enumerable: true
}
});
for ( const myKey in myObject ) {
const myValue = myObject[ myKey ];
if ( Object.hasOwn( myObject, myKey ) ) {
console.log( `${ myKey } : ${ myValue }` );
}
}
> "myProperty : true"
Il existe également trois méthodes statiques qui renvoient chacune un tableau composé d'un
Clés (Object.keys()
), valeurs (Object.values()
) de l'objet pouvant être énumérées ou
des paires clé-valeur (Object.entries()
):
const myObject = { "myProperty" : true, "mySecondProperty" : false };
Object.keys( myObject );
> Array [ "myProperty", "mySecondProperty" ]
Cela vous permet d'itérer des clés d'objet, des valeurs ou des paires clé-valeur (à l'aide de attribution de déstructuration). sans inclure les propriétés appartenant au prototype de cet objet:
const myPrototype = { "protoProperty" : "Non-enumerable property value." };
const myObject = Object.create( myPrototype, {
myProperty: {
value: "Enumerable property value.",
enumerable: true
}
});
for ( const propKey of Object.keys( myObject ) ) {
console.log( propKey );
}
> "myProperty"
for ( const propValue of Object.values( myObject ) ) {
console.log( propValue );
}
> "Enumerable property value."
for ( const [ propKey, propValue ] of Object.entries( myObject ) ) {
console.log( `${ propKey } : ${ propValue }` );
}
> "myProperty : Enumerable property value."
forEach()
Les méthodes forEach()
fournies par le tableau
Carte, Définir,
et les constructeurs NodeList fournissent un raccourci utile pour effectuer des itérations sur des données
dans le contexte d'une fonction de rappel. Contrairement aux autres formes de boucle,
une boucle créée avec une méthode forEach()
ne peut pas être interrompue à l'aide de break
ou
continue
forEach
est une méthode appartenant au prototype de chaque structure de données. Chaque forEach
attend une fonction de rappel en tant qu'argument, bien que celle-ci varie légèrement
des arguments inclus lors de l'appel de cette fonction. Une seconde, facultatif
spécifie une valeur this
à utiliser comme contexte d'appel pour la
de rappel.
La fonction de rappel utilisée avec Array.forEach
fournit des paramètres contenant
la valeur de l'élément actuel, son index et le tableau sur lequel la méthode forEach
a été appelée:
const myArray = [ true, false ];
myArray.forEach( ( myElement, i, originalArray ) => {
console.log( i, myElement, originalArray );
});
> 0 true Array(3) [ true, false ]
> 1 false Array(3) [ true, false ]
La fonction de rappel utilisée avec Map.forEach
fournit des paramètres contenant le
valeur associée à l'élément actuel, la clé associée à l'élément actuel
et le mappage sur lequel la méthode forEach
a été appelée:
const myMap = new Map([
['myKey', true],
['mySecondKey', false ],
]);
myMap.forEach( ( myValue, myKey, originalMap ) => {
console.log( myValue, myKey, originalMap );
});
> true "myKey" Map { myKey → true, mySecondKey → false }
> false "mySecondKey" Map { myKey → true, mySecondKey → false }
Un rappel Set.forEach
inclut des paramètres similaires. Comme Set ne comporte pas
index ou clés distincts des valeurs, le deuxième argument fournit à la place une
des valeurs redondantes et pouvant être ignorées, strictement pour assurer la cohérence de la syntaxe avec le
d'autres méthodes forEach
.
const mySet = new Set([ true, false ]);
mySet.forEach( ( myValue, myKey, originalSet ) => {
console.log( myValue, myKey, originalSet );
});
> true true Set [ true, false ]
> false false Set [ true, false ]
Itérateurs
Un itérable est une structure de données constituée d'éléments individuels pouvant être
en utilisant les approches détaillées précédemment. Un itérateur est un
un objet itérable qui respecte le protocole d'itérateur, ce qui signifie qu'il doit implémenter
Une méthode next()
qui fait défiler les éléments qu'elle contient un par un,
chaque fois que cette méthode est appelée, en renvoyant un objet pour chaque appel
dans un format spécifique.
les structures de données itérables intégrées de JavaScript (telles que
Array
Map (Carte)
Set) ne sont pas des itérateurs dans et de
mais ils héritent tous d'une méthode iterator
, accessible à l'aide de la méthode
@@iterator
symbole bien connu,
qui renvoie un objet itérateur créé à partir de la structure de données itérable:
const myIterable = [ 1, 2, 3 ];
const myIterator = myIterable[ Symbol.iterator ]();
myIterable;
> (3) [1, 2, 3]
myIterator;
> Array Iterator {}
L'appel de la méthode next()
sur un itérateur vous aide à parcourir les éléments qu'il
contient un à la fois, chaque appel renvoyant un objet contenant deux
: value
, qui contient la valeur de l'élément actuel, et
done
, une valeur booléenne indiquant si l'itérateur a transmis le dernier élément dans
la structure des données. La valeur de done
n'est true
que lorsqu'un appel à next()
aboutit à une tentative d'accès à un élément au-delà du dernier élément du
itérateur.
const myIterable = [ 1, 2, 3 ];
const myIterator = myIterable[ Symbol.iterator ]();
myIterator.next();
> Object { value: 1, done: false }
myIterator.next();
> Object { value: 2, done: false }
myIterator.next();
> Object { value: 3, done: false }
myIterator.next();
> Object { value: undefined, done: true }
Fonctions de générateur
Utilisez le mot clé function*
(notez l'astérisque) pour déclarer un générateur
ou définissez une expression de fonction de générateur:
function* myGeneratorFunction() { };
Tout comme les itérateurs, les fonctions de générateur conservent l'état. Appel d'un de générateur renvoie un nouvel objet Generator, mais pas immédiatement exécuter le code dans le corps de la fonction:
function* myGeneratorFunction() {
console.log( "Generator function body ")
};
const myGeneratorObject = myGeneratorFunction();
myGeneratorObject;
> Generator { }
typeof myGeneratorObject;
> "object"
Les objets de générateur respectent le protocole d'itérateur. La valeur attribuée à chaque appel
Sur une fonction de générateur, next()
est déterminé par une expression yield
.
qui met en pause l'exécution de la fonction de générateur et renvoie la valeur de la
Expression contenant le mot clé yield
. Appels ultérieurs au next()
poursuivre l'exécution de la fonction en s'arrêtant à l'expression yield
suivante ;
renvoyant la valeur associée.
function* myGeneratorFunction() {
yield "My first yielded value.";
yield "My second yielded value.";
};
const myGeneratorObject = myGeneratorFunction();
myGeneratorObject.next();
> Object { value: "My first yielded value.", done: false }
myGeneratorObject.next();
> Object { value: "My second yielded value.", done: false }
Lorsque next()
est appelé après qu'aucune autre valeur n'est spécifiée à l'aide de yield
,
return
ou throw
(en cas d'erreur), le reste de la fonction
s'exécute, et la valeur value
de l'objet renvoyé est undefined
et la valeur done
de true
:
function* myGeneratorFunction() {
console.log( "Start of the generator function." );
yield "First";
console.log( "Second part of the generator function." );
yield "Second";
console.log( "Third part of the generator function." );
yield "Third";
};
const myGeneratorObject = myGeneratorFunction();
myGeneratorObject.next();
> "Start of the generator function."
> Object { value: "First", done: false }
myGeneratorObject.next();
> "Second part of the generator function."
> Object { value: "Second", done: false }
myGeneratorObject.next();
> "Third part of the generator function."
> Object { value: "Third", done: false }
myGeneratorObject.next();
> Object { value: undefined, done: true }
N'utilisez next()
que sur l'objet renvoyé par la fonction de générateur, et non sur le
de la fonction de générateur elle-même. Sinon, chaque appel de la fonction de générateur
crée un objet "generator" :
function* myGeneratorFunction() {
yield "First";
yield "Second";
};
myGeneratorFunction().next();
> Object { value: "First", done: false }
myGeneratorFunction().next();
> Object { value: "First", done: false }
Comme pour toute fonction, la fonction de générateur s'arrête lorsqu'elle rencontre un return
.
mot clé. Il renvoie ensuite un objet au contexte d'appel contenant le
a renvoyé une valeur, ainsi qu'une propriété done
avec la valeur true
.
function* myGeneratorFunction() {
yield 1;
yield 2;
return 3;
};
const myGeneratorObject = myGeneratorFunction();
myGeneratorObject.next().done;
> Object { value: 1, done: false }
myGeneratorObject.next().done;
> Object { value: 2, done: false }
myGeneratorObject.next();
> Object { value: 3, done: true }
Une expression yield
peut utiliser une partie de la sémantique d'un identifiant,
permettant une "communication" bidirectionnelle depuis et vers la partie suspendue
du générateur. Lorsqu'une valeur est transmise à la méthode next()
d'un générateur en tant que
un argument, il remplace la valeur associée à l'argument "suspendu"
Expression yield
:
function* myGeneratorFunction() {
const firstYield = yield;
yield firstYield + 10;
};
const myGeneratorObject = myGeneratorFunction();
myGeneratorObject.next();
> Object { value: undefined, done: false }
myGeneratorObject.next( 5 );
> Object { value: 15, done: false }
Gardez à l'esprit que cette opération remplace l'intégralité de l'expression associée à
yield
précédente, et ne réattribue pas simplement la valeur de l'yield
précédente à
la valeur spécifiée dans next()
:
function* myGeneratorFunction() {
const firstYield = yield;
const secondYield = yield firstYield + 100;
yield secondYield + 10;
};
const myGeneratorObject = myGeneratorFunction();
myGeneratorObject.next();
> Object { value: undefined, done: false }
myGeneratorObject.next( 10 ); // Can be thought of as changing the value of the `firstYield` variable to `10
> Object { value: 110, done: false }
myGeneratorObject.next( 20 ); // Can be thought of as changing the value of the `secondYield` variable to `20`, _not_ `20 + 100;`
> Object { value: 30, done: false }
Tout argument transmis au premier appel à next()
est ignoré, car il n'existe pas
précédente expression yield
pour accepter cette valeur. Comme pour toute autre fonction,
les arguments transmis à l'appel initial de la fonction de générateur sont disponibles
le champ d'application du corps de la fonction de générateur:
function* myGeneratorFunction( startingValue ) {
let newValue = yield startingValue + 1;
newValue = yield newValue + 10;
yield startingValue + 20;
};
const myGeneratorObject = myGeneratorFunction( 2 );
myGeneratorObject.next( 1 );
> Object { value: 3, done: false }
myGeneratorObject.next( 5 );
> Object { value: 15, done: false }
myGeneratorObject.next( 10 );
Object { value: 22, done: false }
L'opérateur yield*
(notez l'astérisque) est utilisé avec un itérable, tel que
une autre fonction de générateur, pour itérer et donner à chaque valeur son opérande
renvoie:
function* mySecondaryGenerator() {
yield 2;
yield 3;
}
function* myGenerator() {
yield 1;
yield* mySecondaryGenerator();
yield 4;
return 5;
}
const myIterator = myGenerator();
myIterator.next();
> Object { value: 1, done: false }
myIterator.next();
> Object { value: 2, done: false }
myIterator.next();
> Object { value: 3, done: false }
myIterator.next();
> Object { value: 4, done: false }
myIterator.next();
> Object { value: 5, done: true }
JavaScript asynchrone
Bien que JavaScript soit fondamentalement synchrone, des mécanismes permettant aux développeurs de tirer parti la boucle d'événements pour effectuer des tâches asynchrones.
Promesses
Une promesse est un espace réservé pour une valeur inconnue lorsque la promesse est créé. Il s'agit d'un conteneur qui dicte une opération asynchrone, dont les termes que l'opération est considérée comme ayant réussi ou échoué, les actions à entreprendre dans les deux cas, et la valeur qui en résulte.
Créer une instance Promise à l'aide de l'opérateur new
avec l'Promise
intégré
de la fonction constructeur. Ce constructeur accepte une fonction appelée exécuteur.
comme argument. Cette fonction d'exécuteur est généralement utilisée pour exécuter une ou plusieurs
des actions asynchrones, puis dictez les conditions dans lesquelles la promesse doit être
considéré comme
a été livré ou refusé. Une promesse est définie comme en attente
pendant que la fonction
d’exécuteur est en cours d’exécution. Une fois que l'exécuteur a terminé, une promesse
est considéré comme réussi (ou résolu dans certaines sources) si
la fonction d'exécuteur et l'action asynchrone qu'elle effectue sont terminées.
correctement, et rejetée si la fonction de l'exécuteur rencontre une erreur ; ou
l'action asynchrone en cours d'exécution échoue. Une fois la promesse réalisée ou
refusée, elle est considérée comme réglée.
const myPromise = new Promise( () => { });
Le constructeur appelle la fonction d'exécuteur avec deux arguments. Ces arguments sont des fonctions qui vous permettent d'exécuter ou de refuser manuellement la promesse:
const myPromise = new Promise( ( fulfill, reject ) => { });
Les fonctions utilisées pour exécuter ou rejeter une promesse sont appelées avec le résultat valeur de la promesse en tant qu'argument (généralement une erreur en cas de refus):
const myPromise = new Promise( ( fulfill, reject ) => {
const myResult = true;
setTimeout(() => {
if( myResult === true ) {
fulfill( "This Promise was successful." );
} else {
reject( new Error( "This Promise has been rejected." ) );
}
}, 10000);
});
myPromise;
> Promise { <state>: "pending" }
myPromise;
> Promise { <state>: "fulfilled", <value>: "This Promise was successful." }
Enchaînement de promesses
Vous pouvez agir sur l'objet Promise obtenu à l'aide des propriétés then()
, catch()
et
Méthodes finally()
héritées du constructeur Promise. Chacun de ces éléments
renvoie une promesse qui peut être traitée immédiatement avec then()
,
catch()
ou finally()
, ce qui vous permet d'enchaîner les promesses obtenues.
then()
fournit deux fonctions de rappel en tant qu'arguments. Utiliser la première pour répondre
la promesse résultante et la seconde
à la rejeter. Les deux méthodes n'acceptent qu'un seul
qui donne sa valeur à la promesse obtenue.
const myPromise = new Promise( ( fulfill, reject ) => {
const myResult = true;
setTimeout(() => {
if( myResult === true ) {
fulfill( "This Promise was fulfilled." );
} else {
reject( new Error( "This Promise has been rejected." ) );
}
}, 100);
});
myPromise.then( successfulResult => console.log( successfulResult ), failedResult => console.error( failedResult ) );
> "This Promise was successful."
Vous pouvez également utiliser then()
pour ne gérer que l'état "réussi" et catch
pour
gérer l'état rejeté. Appelez catch
avec un seul argument contenant le
indiquée dans la méthode de rejet de la promesse:
const myPromise = new Promise( ( fulfill, reject ) => {
const myResult = false;
setTimeout(() => {
if( myResult === true ) {
fulfill( "This Promise was fulfilled." );
} else {
reject( new Error( "This Promise has been rejected." ) );
}
}, 100);
});
myPromise
.then( fulfilledResult => console.log(fulfilledResult ) )
.catch( rejectedResult => console.log( rejectedResult ) )
.finally( () => console.log( "The Promise has settled." ) );
> "Error: This Promise has been rejected."
> "The Promise has settled."
Contrairement à then
et catch
, qui permettent à une fonction de gestionnaire de s'exécuter lorsqu'une promesse
est traitée ou rejetée, une fonction transmise en tant qu'argument à finally
est appelée, que la promesse ait été réalisée ou refusée.
La fonction de gestionnaire est appelée sans argument, car elle n'est pas destinée
travailler avec les valeurs transmises par la promesse, uniquement pour exécuter le code après la
La promesse est remplie.
Simultanéité
Le constructeur Promise fournit quatre méthodes pour travailler avec plusieurs
Promesses, à l'aide d'un élément iterable contenant des objets Promise Ces
renvoient chacune une promesse qui est remplie ou rejetée en fonction de l'état
des promesses qui lui sont transmises. Promise.all()
, par exemple, crée une promesse
qui n'est satisfaite que si toutes les promesses transmises à cette méthode sont remplies:
const firstPromise = new Promise( ( fulfill, reject ) => fulfill( "Successful. ") );
const secondPromise = new Promise( ( fulfill, reject ) => fulfill( "Successful. ") );
const thirdPromise = new Promise( ( fulfill, reject ) => fulfill( "Successful. ") );
const failedPromise = new Promise( ( fulfill, reject ) => reject( "Failed.") );
const successfulPromises = [ firstPromise, secondPromise, thirdPromise ];
const oneFailedPromise = [ failedPromise, ...successfulPromises ];
Promise.all( successfulPromises )
.then( ( allValues ) => {
console.log( allValues );
})
.catch( ( failValue ) => {
console.error( failValue );
});
> Array(3) [ "Successful. ", "Successful. ", "Successful. " ]
Promise.all( oneFailedPromise )
.then( ( allValues ) => {
console.log( allValues );
})
.catch( ( failValue ) => {
console.error( failValue );
});
> "Failed."
Les méthodes de simultanéité de Promise sont les suivantes:
Promise.all()
- N'est traité que si toutes les promesses fournies sont remplies.
Promise.any()
- Retirée si l'une des promesses fournies est remplie, mais seulement rejetée si toutes les promesses sont rejetées.
Promise.allSettled()
- sont satisfaites lorsque les promesses ont été conclues, quel que soit leur résultat ;
Promise.race()
- refus ou honorés en fonction du résultat de la première promesse de paiement ; en ignorant toutes les promesses établies ultérieurement.
async
/await
Lorsque vous utilisez le mot clé async
avant une déclaration de fonction
ou expression de fonction, toute
la valeur renvoyée par la fonction est renvoyée sous la forme d'une promesse remplie contenant cette
. Cela vous permet d'exécuter et de gérer des opérations asynchrones à l'aide du même
en tant que développement synchrone.
async function myFunction() {
return "This is my returned value.";
}
myFunction().then( myReturnedValue => console.log( myReturnedValue ) );
> "This is my returned value."
L'expression await
met en pause l'exécution d'une fonction asynchrone tout en
la promesse associée est réglée. Une fois la promesse établie, la valeur
L'expression await
correspond à la valeur honorée ou refusée de la promesse.
async function myFunction() {
const myPromise = new Promise( ( fulfill, reject ) => { setTimeout( () => fulfill( "Successful. "), 5000 ); });
const myPromisedResult = await myPromise;
return myPromisedResult;
}
myFunction()
.then( myResult => console.log( myResult ) )
.catch( myFailedResult => console.error( myFailedResult ) );
> "Successful."
Toute valeur non liée à une promesse incluse dans une expression await
est renvoyée sous forme de
promesse remplie:
async function myFunction() {
const myPromisedResult = await "String value.";
return myPromisedResult;
}
myFunction()
.then( myResult => console.log( myResult ) )
.catch( myFailedResult => console.error( myFailedResult ) );
> "String value."
Testez vos connaissances
Quel type de boucle utilisez-vous pour itérer sur une quantité connue ?
while
for
do...while