The function*
declaration (function
keyword followed by an asterisk) defines a generator function, which returns a Generator
object.
You can also define generator functions using the GeneratorFunction
constructor, or the function expression syntax.
function* name([param[, param[, ... param]]]) { statements }
name
param
statements
Generators are functions which can be exited and later re-entered. Their context (variable bindings) will be saved across re-entrances.
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.
This pattern is what async
functions are built on top of.
Calling a generator function does not execute its body immediately; an iterator object for the function is returned instead. When the iterator's next()
method is called, the generator function's body is executed until the first yield
expression, which specifies the value to be returned from the iterator or, with 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 execution was paused with the argument from next()
.
A return
statement in a generator, when executed, will make the generator finished (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* idMaker() { var index = 0; while (index < index+1) yield index++; } var 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 // ...
function* anotherGenerator(i) { yield i + 1; yield i + 2; yield i + 3; } function* generator(i) { yield i; yield* anotherGenerator(i); yield i + 10; } var 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); } var 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
function* yieldAndReturn() { yield "Y"; return "R"; yield "unreachable"; } var 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 }
function* f() {} var obj = new f; // throws "TypeError: f is not a constructor
const foo = function* () { yield 10; yield 20; }; const bar = foo(); console.log(bar.next()); // {value: 10, done: false}
Specification | Status | Comment |
---|---|---|
ECMAScript 2015 (6th Edition, ECMA-262) The definition of 'function*' in that specification. | Standard | Initial definition. |
ECMAScript 2016 (ECMA-262) The definition of 'function*' in that specification. | Standard | Changed that generators should not have [[Construct]] trap and will throw when used with new . |
ECMAScript Latest Draft (ECMA-262) The definition of 'function*' in that specification. | Draft |
Desktop | ||||||
---|---|---|---|---|---|---|
Chrome | Edge | Firefox | Internet Explorer | Opera | Safari | |
Basic support | 39 | 13 | 26 | No | 26 | 10 |
IteratorResult object instead of throwing |
49 | 13 | 29 | No | Yes | Yes |
Not constructable with new (ES2016) |
Yes | ? | 43 | No | Yes | 10 |
Trailing comma in parameters | ? | ? | 52 | ? | Yes | ? |
Mobile | |||||||
---|---|---|---|---|---|---|---|
Android webview | Chrome for Android | Edge Mobile | Firefox for Android | Opera for Android | iOS Safari | Samsung Internet | |
Basic support | Yes | 39 | Yes | 26 | Yes | 10 | 4.0 |
IteratorResult object instead of throwing |
Yes | Yes | Yes | 29 | Yes | Yes | Yes |
Not constructable with new (ES2016) |
Yes | Yes | ? | 43 | Yes | 10 | Yes |
Trailing comma in parameters | ? | ? | ? | 52 | ? | ? | ? |
Server | |
---|---|
Node.js | |
Basic support | 4.0.0
|
IteratorResult object instead of throwing |
Yes |
Not constructable with new (ES2016) |
Yes |
Trailing comma in parameters | 8.0.0 |
Older Firefox versions implement an older version of the generators proposal. In the older version, generators were defined using a regular function
keyword (without an asterisk) among other differences. See Legacy generator function for further information.
IteratorResult
object returned instead of throwingStarting with Gecko 29 (Firefox 29 / Thunderbird 29 / SeaMonkey 2.26), the completed generator function no longer throws a TypeError
"generator has already finished". Instead, it returns an IteratorResult
object like { value: undefined, done: true }
(bug 958951).
function* expression
GeneratorFunction
objectyield
yield*
Function
objectfunction declaration
function expression
Functions and function scope
© 2005–2018 Mozilla Developer Network and individual 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*