Генераторы - корявые биты

Черновой вариант спецификации ECMAScript 6 уже доставил немало радости современным разработчикам JavaScript. В предыдущем посте мы рассмотрели некоторые новые классы коллекций и циклы for..of . В этом посте мы поговорим о том, что неразрывно связано с циклами for..of : функциях-генераторах.

Уже существует множество замечательных материалов , в которых рассказывается, почему и как использовать генераторы. В двух словах, генераторы — это специальные функции, которые создают итераторы , а итераторы — это объекты, имеющие метод next() , который можно вызвать для получения значения. В функции-генераторе ключевое слово yield предоставляет значение для next() . Использование yield приостанавливает выполнение функции-генератора, сохраняя состояние до тех пор, пока next() не будет вызвана снова, после чего код запускается снова и продолжается до тех пор, пока не будет yield другое значение (или пока функция-генератор не завершится). Существует несколько канонических вариантов использования функций-генераторов, например, их использование для перебора чисел в последовательности Фибоначчи .

Покончив с основами, давайте углубимся в пример JavaScript, который охватывает некоторые ошибки или «грубые моменты» работы с генераторами. Повсюду есть обширные комментарии, и вы можете поиграться с живой версией кода, прежде чем читать его:

Итак, какие важные выводы можно сделать из кода?

Во-первых, создание генератора приводит к созданию уникального итератора со своим собственным состоянием, и вы можете передавать параметры конструктору генератора, который может управлять поведением.

Во-вторых, вы можете передать параметр при вызове метода next() итератора, и это значение будет присвоено всему, что находится в левой части оператора yield из предыдущего вызова итератора. Это отличный способ изменить выходные данные итератора — здесь мы используем его, чтобы контролировать, будет ли полученное слово в верхнем регистре или нет. Если вы хотите повлиять на самое первое полученное значение, сделайте это через параметр конструктора генератора.

Наконец, генераторы могут создавать как конечные, так и бесконечные итераторы. Если вы работаете с бесконечным итератором, убедитесь, что у вас есть какое-то терминальное условие, основанное на значении yield ed — очень легко случайно написать бесконечные циклы, особенно при использовании for..of для итерации. Если вы работаете с конечным итератором посредством вызовов next() , то свойство .done возвращаемого объекта сигнализирует о завершении итерации.

Мы надеемся, что этот образец, а также другие ресурсы, доступные в Интернете, вызовут у вас некоторое волнение и заставят задуматься о том, как можно использовать генераторы в своем собственном коде. Версии Firefox, начиная с 31, и Chrome, начиная с 39, изначально поддерживают генераторы. Проект Regenerator предлагает поддержку генераторов для других браузеров, также можно использовать Traceur.

Спасибо Эрику Арвидссону за помощь в написании этой статьи.