Geradores
No JavaScript um gerador é uma função que retorna uma lista de valores, só que
um por vez. Para conseguirmos o próximo valor, usamos a função next() que
retorna um objeto com o atributo value que é o próximo valor e o atributo
done que indica se a gerador terminou. Além disso é necessário um asterisco *
na frente da função.
Quando um gerador atinge a palavra-chave yield, ele pausa e retorna o valor
atual. Na próxima chamada, o gerador continua a partir do local onde parou.
Por exemplo se quisermos criar um gerador de números de 1 a 10, podemos fazer:
var contador = function* (n) {
  var numero = 1;
  while (numero <= n) {
    yield numero;
    numero++;
  }
};
var gerador = contador(10);
while (true) {
  var proximo = gerador.next();
  // Verifica se a geração terminou
  if (proximo.done) break;
  console.log(proximo.value);
}
Um gerador não necessariamente precisa ter um fim, podemos criar um gerador que vai gerar números infinitamente:
var fibonacci = function* (n) {
  var a = 1,
    b = 1;
  while (true) {
    yield a;
    var temp = a;
    a = b;
    b = temp + b;
  }
};
var gerador = fibonacci();
while (true) {
  var proximo = gerador.next();
  // Verifica se a geração terminou (nunca vai acontecer)
  if (proximo.done) break;
  console.log(proximo.value);
}
// Resultado: 1, 1, 2, 3, 5, 8, 13, ... (infinitamente)
Ainda existe a sintaxe yield* que serve para chamar um gerador de outro
gerador. Por exemplo:
var contador1 = function* (n) {
  var numero = 1;
  while (numero <= n) {
    yield numero;
    numero++;
  }
};
var contador2 = function* (n) {
  var numero = 1;
  while (numero <= n) {
    yield* contador1(numero);
    numero++;
  }
};
var gerador = contador2(4);
while (true) {
  var proximo = gerador.next();
  // Verifica se a geração terminou
  if (proximo.done) break;
  console.log(proximo.value);
}
// Resultado: 1,  1, 2,  1, 2, 3,  1, 2, 3, 4