
Генераторные функции — это функции, которые имеют возможность приостановить выполнение на неопределенный период, когда они обнаруживают «урожайность».
Давайте сравним функции генератора со скромной функцией, о которой мы все знаем —
function add() {
let x=1;
let y=2;
return x+y
}
Когда функция «добавить» выполняется, выполнение происходит построчно — сначала определяется x, определяется y и, наконец, возвращается x+y. Вы можете приостановить казнь? Что ж, возможно, вы могли бы использовать обещание, но это не полная приостановка; когда обещание разрешается, выполнение возвращается. С генераторами блок кода, вызвавший генератор, может приостанавливать или возобновлять выполнение.
function* panCakeInstructions() {
yield “Sift flour, baking powder, salt, and sugar”;
yield “Mix milk, egg, and butter”;
yield “Scoop batter on pan”;
yield “Serve hot when brown on both sides”;
}
При вызове генератора panCakeInstructions создается и возвращается итератор.
let instructions = panCakeInstructions();instructions.next().value //Sift flour, baking powder, salt, and sugar instructions.next().value //Mix milk, egg, and butter instructions.next().value //Scoop batter on pan instructions.next().value //Serve hot when brown on both sides
Здорово! Что такое итератор?
ES6, помимо введения новых собственных функций и элегантного синтаксиса, также представил «протоколы». Протоколы — это соглашения по стандартизации использования. Следуя протоколам, мы все можем счастливо сосуществовать и хорошо играть друг с другом.
Протокол итератора
Объект называется итератором, если он имеет интерфейс next(), который возвращает {value: ‹any›: done: Boolean}. Полученное значение возвращается вместе с логическим флагом «готово», чтобы указать, выдал ли генератор свое последнее значение.
Итерируемый протокол
Объект является итерируемым, если он реализует «Symbol.iterator».
Хорошо, тайм-аут! Давайте на секунду поговорим о Symbol.iterator.
Symbol.iterator, согласно mdn, — это «функция с нулевыми аргументами, которая возвращает объект, соответствующий протоколу итератора». Это хорошее объяснение, но давайте посмотрим на это в действии.
Вызвав функцию Symbol.iterator, мы смогли выполнить итерацию с объектом итератора.
Вернемся к нашей функции panCakeInstructions. С помощью генераторов мы смогли приостановить выполнение функции, шаг за шагом переходить к инструкциям, выдавая (возвращая) результаты при вызове next() вызывающей стороной.
Кроме того, поскольку функция Generator возвращает итератор, мы также можем использовать for..of, который был специально введен для этой цели — для перебора итерируемых объектов.
for (const val of panCakeInstructions()){
console.log(val)
}
До Async/Await генераторы были образом жизни людей, которые хотели писать асинхронный код синхронным способом. Co, библиотека на основе генератора Node.js, стала огромным хитом среди разработчиков.
co(function *() {
let breeds = yield getBreeds();
let winner = yield getWinner(breeds);
return winner;
}).catch(function(err) {
console.error(err);
});
Функция-оболочка co принимает функцию генератора, приостанавливает ее до тех пор, пока полученное обещание не будет разрешено, и продвигается вперед. Дополнительные примеры см. в документации co.
В заключение, генераторы хороши, если у вас есть список элементов для повторения, приостановки и возобновления обработки в зависимости от необходимости. Например, бесконечная загрузка/прокрутка — после загрузки начального набора элементов вы можете приостановить загрузку данных и возобновить ее в зависимости от взаимодействия с пользователем.
Ссылки:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols
Первоначально опубликовано на javascriptstore.com 27 февраля 2018 г.