function*
Baseline Широко доступно
Эта функция хорошо зарекомендовала себя и работает на многих устройствах и версиях браузеров. Она доступна во всех браузерах с сентября 2016 года.
Объявление function* создает привязку новой функции-генератора к заданному имени. Функция-генератор может быть прервана и повторно начата позже, при этом ее контекст (привязки переменных) сохраняется между повторными запусками.
Вы также можете определять функции-генераторы с помощью function* выражения.
Попробуйте
function* generator(i) {
yield i;
yield i + 10;
}
const gen = generator(10);
console.log(gen.next().value);
// Expected output: 10
console.log(gen.next().value);
// Expected output: 20
Синтаксис
function* name(param0) {
statements
}
function* name(param0, param1) {
statements
}
function* name(param0, param1, /* …, */ paramN) {
statements
}
Примечание: Функции-генераторы не имеют аналогов стрелочных функций.
Примечание: function и * являются отдельными токенами, поэтому их можно разделять пробельными символами или терминаторами строк.
Параметры
-
name - Имя функции.
-
paramНеобязательно - Имя формального параметра для функции. Синтаксис параметров см. в справке по функциям.
-
statementsНеобязательно - Инструкции, составляющие тело функции.
Описание
Объявление function* создает объект GeneratorFunction. Каждый раз, когда вызывается функция-генератор, она возвращает новый объект Generator, который соответствует протоколу итератора. Выполнение функции-генератора приостанавливается в некотором месте, которое изначально находится в самом начале тела функции. Функция-генератор может быть вызвана несколько раз для создания нескольких генераторов одновременно; каждый генератор поддерживает свой собственный контекст выполнения функции-генератора и может выполняться независимо.
Генератор обеспечивает двунаправленный поток управления: поток управления может передаваться между функцией-генератором (вызываемой стороной) и ее вызывающей стороной столько раз, сколько обе стороны пожелают. Поток управления может идти от вызывающей стороны к вызываемой стороной путем вызова методов генератора: next(), throw() и return(). Поток управления может идти от вызываемой стороны к вызывающей путем нормального завершения функции с помощью return или throw или выполнения всех инструкций, или с помощью выражений yield и yield*.
Когда вызывается метод next() генератора, тело функции-генератора выполняется до тех пор, пока не произойдет одно из следующих событий:
- Выражение
yield. В этом случае методnext()возвращает объект со свойствомvalue, содержащим возвращаемое значение, и свойствомdone, которое всегда равноfalse. При следующем вызовеnext()выражениеyieldоценивается как значение, переданное вnext(). yield*, делегирующий другому итератору. В этом случае этот вызов и любые будущие вызовыnext()для генератора эквивалентны вызовуnext()для делегированного итератора до тех пор, пока делегированный итератор не будет завершен.- Оператор
return(который не перехваченtry...catch...finally) или конец потока управления, что подразумеваетreturn undefined. В этом случае генератор завершается, а методnext()возвращает объект со свойствомvalue, содержащим возвращаемое значение, и свойствомdone, которое всегда равноtrue. Любые последующие вызовыnext()не имеют эффекта и всегда возвращают{ value: undefined, done: true }. - Возникает ошибка внутри функции, либо через оператор
throw, либо через необработанное исключение. Методnext()выбрасывает эту ошибку, и генератор завершается. Любые последующие вызовыnext()не имеют эффекта и всегда возвращают{ value: undefined, done: true }.
Когда вызывается метод throw() генератора, он действует так, как если бы в теле генератора в текущей приостановленной позиции был вставлен оператор throw. Аналогично, когда вызывается метод return() генератора, он действует так, как если бы в теле генератора в текущей приостановленной позиции был вставлен оператор return. Оба метода обычно завершают генератор, если только функция-генератор не перехватывает завершение через try...catch...finally.
Генераторы ранее были парадигмой асинхронного программирования, позволяющей избежать Callback Hell путем достижения Инверсии управления. В настоящее время эта задача решается более простой моделью асинхронных функций и объектом Promise. Однако генераторы по-прежнему полезны для многих других задач, таких как простое определение итераторов.
Объявления function* ведут себя аналогично объявлениям function — они поднимаются в начало своей области видимости и могут быть вызваны в любом месте своей области видимости, и их можно переопределить только в определенных контекстах.
Примеры
Базовый пример
function* idMaker() {
let index = 0;
while (true) {
yield index++;
}
}
const gen = idMaker();
console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
console.log(gen.next().value); // 3
// …
Пример с yield*
function* anotherGenerator(i) {
yield i + 1;
yield i + 2;
yield i + 3;
}
function* generator(i) {
yield i;
yield* anotherGenerator(i);
yield i + 10;
}
const gen = generator(10);
console.log(gen.next().value); // 10
console.log(gen.next().value); // 11
console.log(gen.next().value); // 12
console.log(gen.next().value); // 13
console.log(gen.next().value); // 20
Передача аргументов в генераторы
function* logGenerator() {
console.log(0);
console.log(1, yield);
console.log(2, yield);
console.log(3, yield);
}
const gen = logGenerator();
// the first call of next executes from the start of the function
// until the first yield statement
gen.next(); // 0
gen.next("pretzel"); // 1 pretzel
gen.next("california"); // 2 california
gen.next("mayonnaise"); // 3 mayonnaise
Оператор return в генераторе
function* yieldAndReturn() {
yield "Y";
return "R";
yield "unreachable";
}
const gen = yieldAndReturn();
console.log(gen.next()); // { value: "Y", done: false }
console.log(gen.next()); // { value: "R", done: true }
console.log(gen.next()); // { value: undefined, done: true }
Генератор как свойство объекта
const someObj = {
*generator() {
yield "a";
yield "b";
},
};
const gen = someObj.generator();
console.log(gen.next()); // { value: 'a', done: false }
console.log(gen.next()); // { value: 'b', done: false }
console.log(gen.next()); // { value: undefined, done: true }
Генератор как метод объекта
class Foo {
*generator() {
yield 1;
yield 2;
yield 3;
}
}
const f = new Foo();
const gen = f.generator();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: false }
console.log(gen.next()); // { value: undefined, done: true }
Генератор как вычисляемое свойство
class Foo {
*[Symbol.iterator]() {
yield 1;
yield 2;
}
}
const SomeObj = {
*[Symbol.iterator]() {
yield "a";
yield "b";
},
};
console.log(Array.from(new Foo())); // [ 1, 2 ]
console.log(Array.from(SomeObj)); // [ 'a', 'b' ]
Генераторы не являются конструкторами
function* f() {}
const obj = new f(); // throws "TypeError: f is not a constructor
Пример генератора
function* powers(n) {
// Endless loop to generate
for (let current = n; ; current *= n) {
yield current;
}
}
for (const power of powers(2)) {
// Controlling generator
if (power > 32) {
break;
}
console.log(power);
// 2
// 4
// 8
// 16
// 32
}
Спецификации
Совместимость с браузерами
| Desktop | Mobile | Server | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Chrome | Edge | Firefox | Opera | Safari | Chrome Android | Firefox for Android | Opera Android | Safari on iOS | Samsung Internet | WebView Android | WebView on iOS | Bun | Deno | Node.js | |
generator_function |
39 |
13 |
26 |
26 |
10 |
39 |
26 |
26 |
10 |
4.0 |
39 |
10 |
1.0.0 |
1.0 |
4.0.0 |
IteratorResult_object |
49 |
13 |
29 |
36 |
10 |
49 |
29 |
36 |
10 |
5.0 |
49 |
10 |
1.0.0 |
1.0 |
6.0.0 |
not_constructable_with_new |
50 |
13 |
43 |
37 |
10 |
50 |
43 |
37 |
10 |
5.0 |
50 |
10 |
1.0.0 |
1.0 |
6.0.0 |
trailing_comma_in_parameters |
58 |
14 |
52 |
45 |
10 |
58 |
52 |
43 |
10 |
7.0 |
58 |
10 |
1.0.0 |
1.0 |
8.0.0 |
См. также
- Руководство по функциям
- Руководство по итераторам и генераторам
- Функции
GeneratorFunctionfunction*выражениеfunctionasync functionasync function*- Протоколы итерации
yieldyield*Generator- Regenerator на GitHub
- Promises and Generators: control flow utopia презентация Forbes Lindesay на JSConf (2013)
- Task.js на GitHub
- You Don't Know JS: Async & Performance, Ch.4: Generators от Kyle Simpson
© 2005–2025 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*