ECMAScript 2015: Generators

ES2015 Gotchas é uma série quinzenal sobre as novidades e pegadinhas do ES2015.

Juntamente com os Symbols, Generators é uma das features novas do ES2015 que mais gera confusão, seja pela sua sintaxe estranha ou por trazer um conceito até então sem precedentes na linguagem.

Indo diretamente ao ponto, generator é uma função que pode ser pausada infinitamente, podendo retornar valores parciais ou específicos a cada pausa, trabalhando em uma estrutura iterável, podendo ser usados nos novos loopings for...of do ES2015. Veja o exemplo abaixo:

function* sayHello() {  
  yield "Ola";
  yield "mundo!";
}

for(let i of sayHello())  
  console.log(i);
// "Ola"
// "mundo!"

Destrinchando a Mágica

Parece magia, não? Mas vamos com calma. É importante notar que a primeira vez que executamos uma função geradora, ela não retorna o valor de sua primeira pausa diretamente. Em vez disso, é retornado um objeto iterável, contendo alguns métodos, como o principal next(), que por sua vez retorna o valor dessa pausa e informa se ainda existem outras iterações. Confuso? Vamos ver o que acontece quando chamamos um generator na mão, fora de um looping:

function* contar(ate) {  
  for(let i = 1; i <= ate; i++)
    yield i;
}

> let iterator = contar(3);
  [object Generator]
> iterator.next()
  { value: 1, done: false }
> iterator.next()
  { value: 2, done: false }
> iterator.next()
  { value: 3, done: false }
> iterator.next()
  { value: undefined, done: true }

Tudo pode ser iterável agora!

A partir do ES2015, todo objeto pode ser configurado para iterar automaticamente, usando os novos Symbols, podemos construir manualmente o mecanismo com a interface necessária, ou resolver tudo em poucas linhas usando generators, e ainda delegar o trabalho para outro objeto já iterável. Veja a mágica acontecendo:

class MinhaColecao {  
  constructor() {
    this.array = [1,2,3];
  }
  [Symbol.iterator]: function*(){
    yield* this.array;
  }
}

const magica = new MinhaColecao();  
for(let item of magica)  
  console.log(item);
// 1
// 2
// 3

Generators + Promises = Async / Await

Generators e Promises foram a evolução natural do JavaScript, nos dando ferramentas para escrever códigos assíncronos melhores, e fugir do famigerado callback hell. E logo surgiram experimentos de como utilizar essas duas ferramentas juntas, inclusive novos frameworks baseados nesse novo paradigma, como o Koa em sua primeira versão.

Alguns desses experimentos talvez nunca cheguem a maturidade, porém eles demonstraram que precisávamos de ferramentas ainda melhores e maduras, dando nascimento a nova grande feature: async / await proposta para o ES7 / ES2016.

Com a proposta já madura e praticamente fechada, já podemos usar o novo async / await através de transpilers. Toda a comunidade, e grandes projetos como o Koa, já estão se adequando para esse novo paradigma.

Caso tenha ficado empolgado com o uso e aplicações de generators e queira uma referência completa, sugerimos o ótimo artigo da Mozzila (em inglês).

Até a próxima! Fiquem ligados na série ES2015 Gotchas!

William Grasel

Read more posts by this author.