Generadores: las partes más importantes

El borrador de la especificación de ECMAScript 6 ya ha generado muchas fuentes de alegría para los desarrolladores modernos de JavaScript. En una publicación anterior, hablamos de algunas clases de colecciones nuevas y de bucles de iteración for..of. En esta publicación, hablaremos de algo que va de la mano con los bucles for..of: las funciones de generador.

Ya hay una gran cantidad de material de calidad que aborda el por qué y el cómo usar generadores. En pocas palabras, los generadores son funciones especiales que crean iteradores, y los iteradores son objetos que tienen un método next(), al que se puede llamar para obtener un valor. Dentro de una función generadora, la palabra clave yield proporciona el valor para next(). El uso de yield suspende la ejecución de la función generadora y conserva el estado hasta que se vuelva a llamar a next(), momento en el que el código se reinicia y continúa hasta que yield otro valor (o hasta que finaliza la función generadora). Existen varios casos de uso canónicos para las funciones generadoras, como usarlas para iterar sobre los números de la secuencia de Fibonacci.

Ahora que tenemos los conceptos básicos, analicemos en detalle un ejemplo de JavaScript que abarca algunos de los problemas de trabajar con generadores. Hay comentarios extensos en todo el código, y puedes probar la versión en vivo antes de leerlo:

Entonces, ¿cuáles son algunas de las conclusiones importantes del código?

En primer lugar, la construcción de un generador genera un iterador único con su propio estado distinto, y puedes pasar parámetros al constructor del generador que pueden controlar el comportamiento.

En segundo lugar, puedes pasar un parámetro cuando llames al método next() de un iterador, y ese valor se asignará a lo que esté a la izquierda de la sentencia yield de la invocación del iterador anterior. Esta es una excelente manera de variar el resultado del iterador. Aquí, lo usamos para controlar si la palabra que se genera está en mayúsculas o no. Si deseas influir en el primer valor que se genera, hazlo a través de un parámetro para el constructor del generador.

Por último, los generadores pueden producir iteradores finitos o infinitos. Si trabajas con un iterador infinito, asegúrate de tener algún tipo de condición de finalización basada en el valor yield. Es muy fácil escribir bucles infinitos por accidente, especialmente cuando se usa for..of para la iteración. Si trabajas con un iterador finito a través de llamadas a next(), la propiedad .done del objeto que se muestra indica si la iteración está completa.

Esperamos que esta muestra, junto con los otros recursos disponibles en la Web, te resulte interesante y te haga pensar en cómo puedes usar generadores en tu propio código. Las versiones de Firefox a partir de la 31 y de Chrome a partir de la 39 admiten generadores de forma nativa. El proyecto Regenerator ofrece compatibilidad con generadores para otros navegadores, y también es una opción usar Traceur.

Gracias a Erik Arvidsson por su ayuda para revisar este artículo.