We're looking for a user researcher to understand the needs of developers and designers. Is this you or someone you know? Check out the post: https://mzl.la/2IGzdXS

La déclaration function* (le mot-clé function suivi par un astérisque) permet de définir un générateur (aussi appelé une fonction génératrice) (un générateur est un objet Generator).

Il est également possible de définir un générateur en utilisant le constructeur GeneratorFunction et une expression function*.

Syntaxe

function* nom([param1[, param2[, ... paramN]]]) {
   instructions
}
nom
Le nom de la fonction.
paramN
Le nom d'un paramètre formel passé à la fonction.
instructions
Les instructions qui constituent le corps de la fonction.

Description

Les générateurs sont des fonctions qu'il est possible de quitter puis de reprendre. Le contexte d'un générateur (les liaisons avec ses variables) est sauvegardé entre les reprises successives.

Les générateurs, combinés avec les promesses, sont des outils de programmation asynchrones puissants qui permettent de réduire les inconvénients causés par les callbacks (fonctions de rappel) et l'inversion de contrôle. C'est sur cette combinaison que sont construites les fonctions asynchrones.

Lorsqu'on appelle une fonction génératrice, son corps n'est pas exécuté immédiatement, c'est un itérateur qui est renvoyé pour la fonction. Lorsque la méthode next() de l'itérateur est appelée, le corps de la fonction génératrice est utilisé jusqu'à ce que la première expression yield soit trouvée. Cette expression définira la valeur à renvoyer pour l'itérateur. Si on utilise yield*, on pourra déléguer la génération des valeurs à une autre fonction génératrice. La méthode next() renvoie un objet dont la propriété value contient la valeur générée et une propriété done qui indique si le générateur a produit sa dernière valeur ou non. Lorsqu'on appelle la méthode next() avec un argument, cela reprendra l'exécution de la fonction génératrice et remplacera la valeur de l'expression yield (là où l'exécution avait été interrompue) avec la valeur de l'argument passé à next().

On peut utiliser une instruction return dans un générateur. Lorsque cette instruction sera exécutée, le générateur sera terminé (done vaudra true). La valeur renvoyée par l'instruction return sera la valeur de terminaison du générateur. Une fois qu'un générateur est terminé, il ne peut plus produire d'autres valeurs.

À l'instar d'une instruction return, une exception levée à l'intérieur du générateur entraînera la terminaison du générateur sauf si cette exception est interceptée. Lorsqu'un générateur est terminé, les appels suivants à next() n'exécuteront aucun code provenant du générateur, ils renverront simplement un objet de la forme {value: undefined, done: true}.

Exemples

Exemple simple

function* creerID(){
  var index = 0;
  while(index < 3){
    yield index++;
  }
}

var gen = creerID();

console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
console.log(gen.next().value); // undefined

Exemple utilisant des arguments

function* logGenerator() {
  console.log(yield);
  console.log(yield);
  console.log(yield);
}

var gen = logGenerator();

// le premier appel à next exécute la fonction depuis son 
// début jusqu'au premier yield rencontré
gen.next(); 
gen.next('bretzel');    // bretzel
gen.next('california'); // california
gen.next('mayonnaise'); // mayonnaise

Exemple utilisant yield*

function* autreGenerateur(i) {
  yield i + 1;
  yield i + 2;
  yield i + 3;
}
function* generateur(i){
  yield i;
  yield* autreGenerateur(i);
  yield i + 10;
}

var gen = generateur(10);

console.log(gen.next().value); // 10
console.log(gen.next().value); // 11
console.log(gen.next().value); // 12
console.log(gen.next().value); // 13
console.log(gen.next().value); // 20

Utilisation de return

function* yieldAndReturn() {
  yield "Y";
  return "R";
  yield "inaccessible";
}

var gen = yieldAndReturn();

console.log(gen.next()); // { value: "Y", done: false }
console.log(gen.next()); // { value: "R", done: true }
console.log(gen.next()); // { value: undefined, done: true }

Les générateurs ne sont pas constructibles

function* f() {}
var obj = new f; // lève une TypeError: f n'est pas un constructeur

Générateur défini avec une expression

const toto = function* () {
  yield 10;
  yield 20;
};
const truc = toto();
console.log(truc.next()); // {value: 10, done: false}

Spécifications

Spécification État Commentaires
ECMAScript 2015 (6th Edition, ECMA-262)
La définition de 'function*' dans cette spécification.
Standard Définition initiale
ECMAScript 2016 (ECMA-262)
La définition de 'function*' dans cette spécification.
Standard Les générateurs ne doivent pas gérer la trappe [[Construct]] et déclencher une exception s'ils sont utilisés avec new.
ECMAScript Latest Draft (ECMA-262)
La définition de 'function*' dans cette spécification.
Projet  

Compatibilité des navigateurs

FonctionnalitéChromeEdgeFirefoxInternet ExplorerOperaSafari
Support simple391326 Non2610
IteratorResult object instead of throwing491329 Non Oui Oui
Not constructable with new (ES2016) Oui ?43 Non Oui10
Trailing comma in parameters ? ?52 ? Oui ?
FonctionnalitéAndroid webviewChrome for AndroidEdge mobileFirefox for AndroidOpera AndroidiOS SafariSamsung Internet
Support simple Oui39 Oui26 Oui104.0
IteratorResult object instead of throwing Oui Oui Oui29 Oui Oui Oui
Not constructable with new (ES2016) Oui Oui ?43 Oui10 Oui
Trailing comma in parameters ? ? ?52 ? ? ?

Notes spécifiques à Firefox

Les générateurs et itérateurs dans Firefox pour les versions antérieures à Firefox 26

Les anciennes versions de Firefox implémentaient une ancienne version de la proposition pour les générateurs. Dans cette version, les générateurs étaient définis avec le mot-clé function (sans astérisque) et étaient différents selon d'autres aspects. Voir la page sur les générateurs historiques pour plus d'informations.

IteratorResult au lieu d'une exception

À partir de Gecko 29 (Firefox 29 / Thunderbird 29 / SeaMonkey 2.26), lorsqu'un générateur est terminé, il ne renvoie plus une exception TypeError « generator has already finished ». Il renvoie désormais un objet IteratorResult comme { value: undefined, done: true } (bug 958951).

Voir aussi

Étiquettes et contributeurs liés au document

Contributeurs à cette page : SphinxKnight, risq, fscholz
Dernière mise à jour par : SphinxKnight,