Генераторы
Обычные функции возвращают только одно-единственное значение (или ничего).
Генераторы - это специальный тип функции, который работает как фабрика итераторов.
Для объявления генератора используется новая синтаксическая конструкция: function* (ключевое слово function со звёздочкой).
function* gen() {
yield 1;
yield 2;
yield 3;
}
const iterator = gen()Вызов генератора создает объект класса Generator, который является итерируемым (iterable), т. е. его можно перебирать в цикле for..of или просто вызывая метод next(), при этом никакой код внутри генератора пока не выполняется.
Каждый вызов метода next() у созданного итератора запустить выполнение кода до первого yield, после чего будет возвращено значение, указанное в нем.
// 1
console.log(iterator.next())
// [2, 3]
console.log(...iterator)Передача параметров в метод next
В метод next можно передать значение, которое будет возвращено yield:
function* gen() {
let i = 0
while (true) {
const param = yield i
console.log(param)
if (param) {
break
}
i++
}
}
const iterator = gen()
iterator.next() // { value: 0, done: false }
iterator.next(true) // { value: 1, done: false }
iterator.next() // { value: undefined, done: true }Метод throw
У генераторов есть метод throw, который позволяет бросить исключение внутри генератора.
function* gen() {
try {
// в этой строке возникнет ошибка
let result = yield "Сколько будет 2 + 2?"; // (**)
alert("выше будет исключение ^^^");
} catch(e) {
alert(e); // выведет ошибку
}
}
let generator = gen();
let question = generator.next().value;
generator.throw(new Error("ответ не найден в моей базе данных")); // (*)«Вброшенная» в строке (*) ошибка возникает в строке с yield (**). Далее она обрабатывается как обычно. В примере выше она перехватывается try..catch и выводится.
Подробнее:
Метод return
У генераторов есть метод return(value), которое останавливает работу генератора.
function* gen() {
yield 1;
yield 2;
yield 3;
}
var g = gen();
g.next(); // { value: 1, done: false }
g.return('foo'); // { value: "foo", done: true }
g.next(); // { value: undefined, done: true }Если return(value) вызывает генератор, который находится в уже "завершённом" состоянии, генератор останется в "завершённом" состоянии. Если аргумент не был передан, свойство value вернёт тот же объект, что и .next(). Если аргумент был передан, он будет установлен как значение свойства value возвращаемого объекта.
Подробнее: MDN.
Композиция генераторов
Для генераторов есть особый синтаксис yield*, который позволяет «вкладывать» генераторы один в другой (осуществлять их композицию). Пример:
function* generateSequence(start, end) {
for (let i = start; i <= end; i++) yield i
}
function* generatePasswordCodes() {
// 0..9
yield* generateSequence(48, 57)
// A..Z
yield* generateSequence(65, 90)
// a..z
yield* generateSequence(97, 122)
}
let str = ''
for(let code of generatePasswordCodes()) {
str += String.fromCharCode(code)
}
alert(str)Примечания
Нельзя определить стрелочную функцию генератор, стандартом определен только синтаксис
function*
Last updated