function*
The function*
declaration creates a {{Glossary("binding")}} of a new generator function to a given name. A generator function can be exited and later re-entered, with its context (variable {{Glossary("binding", "bindings")}}) saved across re-entrances.
You can also define generator functions using the function*
expression.
{{EmbedInteractiveExample("pages/js/statement-functionasterisk.html")}}
Syntax
function* name(param0) {
statements
}
function* name(param0, param1) {
statements
}
function* name(param0, param1, /* …, */ paramN) {
statements
}
[!NOTE] Generator functions do not have arrow function counterparts.
Note:
function
and*
are separate tokens, so they can be separated by whitespace or line terminators.
Parameters
name
- : The function name.
param
{{optional_inline}}- : The name of a formal parameter for the function. For the parameters' syntax, see the Functions reference.
statements
{{optional_inline}}- : The statements comprising the body of the function.
Description
A function*
declaration creates a {{jsxref("GeneratorFunction")}} object. Each time a generator function is called, it returns a new {{jsxref("Generator")}} object, which conforms to the iterator protocol. When the iterator's next()
method is called, the generator function's body is executed until the first
{{jsxref("Operators/yield", "yield")}} expression, which specifies the value to be
returned from the iterator or, with {{jsxref("Operators/yield*", "yield*")}}, delegates
to another generator function. The next()
method returns an object with a
value
property containing the yielded value and a done
property which indicates whether the generator has yielded its last value, as a boolean.
Calling the next()
method with an argument will resume the generator
function execution, replacing the yield
expression where an execution was
paused with the argument from next()
.
Generators in JavaScript — especially when combined with Promises — are a very powerful tool for asynchronous programming as they mitigate — if not entirely eliminate -- the problems with callbacks, such as Callback Hell and Inversion of Control. However, an even simpler solution to these problems can be achieved with {{jsxref("Statements/async_function", "async functions", "", 1)}}.
A return
statement in a generator, when executed, will make the generator
finish (i.e. the done
property of the object returned by it will be set to
true
). If a value is returned, it will be set as the value
property of the object returned by the generator.
Much like a return
statement, an error thrown inside the generator will
make the generator finished — unless caught within the generator's body.
When a generator is finished, subsequent next()
calls will not execute any
of that generator's code, they will just return an object of this form:
{value: undefined, done: true}
.
function*
declarations behave similar to {{jsxref("Statements/function", "function")}} declarations — they are hoisted to the top of their scope and can be called anywhere in their scope, and they can be redeclared only in certain contexts.
Examples
Simple example
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
// …
Example with 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
Passing arguments into Generators
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 statement in a generator
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 }
Generator as an object property
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 }
Generator as an object method
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 }
Generator as a computed property
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' ]
Generators are not constructable
function* f() {}
const obj = new f(); // throws "TypeError: f is not a constructor
Generator defined in an expression
const foo = function* () {
yield 10;
yield 20;
};
const bar = foo();
console.log(bar.next()); // {value: 10, done: false}
Generator example
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
}
Specifications
Browser compatibility
See also
- Functions guide
- Iterators and generators guide
- Functions
- {{jsxref("GeneratorFunction")}}
function*
expression- {{jsxref("Statements/function", "function")}}
- {{jsxref("Statements/async_function", "async function")}}
- {{jsxref("Statements/async_function*", "async function*")}}
- Iteration protocols
- {{jsxref("Operators/yield", "yield")}}
- {{jsxref("Operators/yield*", "yield*")}}
- {{jsxref("Generator")}}
- Regenerator on GitHub
- Promises and Generators: control flow utopia presentation by Forbes Lindesay at JSConf (2013)
- Task.js on GitHub
- You Don't Know JS: Async & Performance, Ch.4: Generators by Kyle Simpson