var x = function * (){yield undefined;}
console.log(x.constructor.name === 'GeneratorFunction')
-------------------------------------------------------------------
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.Syntax
Section
function* name([param[, param[, ... param]]]) { statements }
name
- The function name.
param
- The name of a formal parameter for the function.
statements
- The statements comprising the body of the function.
Description
Section
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}
.Examples
Section
Simple example
Section
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
// ...
Example with yield*
Section
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
Passing arguments into Generators
Section
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
Return statement in a generator
Section
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 }
Generators are not constructable
Section
function* f() {}
var obj = new f; // throws "TypeError: f is not a constructor
Generator defined in an expression
Section
const foo = function* () {
yield 10;
yield 20;
};
const bar = foo();
console.log(bar.next()); // {value: 10, done: false}
-------------------------------------------
The Generator
object is returned by a generator function and it conforms to both the iterable protocol and the iterator protocol.Syntax
區段
function* gen() { yield 1; yield 2; yield 3; } var g = gen(); // "Generator { }"Methods
區段
Generator.prototype.next()
- Returns a value yielded by the
yield
expression. Generator.prototype.return()
- Returns the given value and finishes the generator.
Generator.prototype.throw()
- Throws an error to a generator (also finishes the generator, unless caught from within that generator).
Example
區段
An infinite iterator
區段
function* idMaker() {
var index = 0;
while(true)
yield index++;
}
var gen = idMaker(); // "Generator { }"
console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
// ...
Legacy generator objects
區段
Firefox (SpiderMonkey) also implemented an earlier version of generators in JavaScript 1.7, where the star (*) in the function declaration was not necessary (you just use theyield
keyword in the function body). However, legacy generators support has
been removed since Firefox 58 (released on January 23, 2018) (bug 1083482).Legacy generator methods
區段
Generator.prototype.next()
- Returns a value yielded by the
yield
expression. This corresponds tonext()
in the ES2015 generator object. Generator.prototype.close()
- Closes the generator, so that when calling
next()
anStopIteration
error will be thrown. This corresponds to thereturn()
method in the ES2015 generator object. Generator.prototype.send()
- Used to send a value to a generator. The value is returned from the
yield
expression, and returns a value yielded by the nextyield
expression.send(x)
corresponds tonext(x)
in the ES2015 generator object. Generator.
prototype.
throw()
- Throws an error to a generator. This corresponds to the
throw()
method in the ES2015 generator object.
Legacy generator example
區段
function* fibonacci() {
var a = yield 1;
yield a * 2;
}
var it = fibonacci();
console.log(it); // "Generator { }"
console.log(it.next()); // 1
console.log(it.send(10)); // 20
console.log(it.close()); // undefined
console.log(it.next()); // throws StopIteration (as the generator is now closed)