5.2 ES6 Generator Function
Category ES6 Tutorial
ES6 introduced the Generator function, which can suspend the flow of function execution using the yield
keyword, providing a way to alter execution flow and offering a solution for asynchronous programming.
Basic Usage
Generator Function Composition
A Generator function differs from a regular function in two aspects:
- It has an asterisk (
*
) after thefunction
keyword and before the function name. - It contains
yield
expressions within its body.
The asterisk is used to denote that the function is a Generator function, and yield
is used to define the internal states of the function.
function* func(){
console.log("one");
yield '1';
console.log("two");
yield '2';
console.log("three");
return '3';
}
Execution Mechanism
Calling a Generator function is similar to calling a regular function, by appending ()
after the function name. However, unlike regular functions, a Generator function does not execute immediately. Instead, it returns a pointer to the internal state object. To execute the function, you need to call the next
method of the iterator object, which starts execution from the beginning of the function or from the last paused point.
f.next();
// one
// {value: "1", done: false}
f.next();
// two
// {value: "2", done: false}
f.next();
// three
// {value: "3", done: true}
f.next();
// {value: undefined, done: true}
The first call to next
starts execution from the beginning of the Generator function, prints "one", and pauses at the first yield
, returning an object with the value of the expression following yield
and done
set to false
.
The second call to next
resumes execution from the previous pause point, and the process repeats.
The third call prints "three", executes the return statement, and returns an object with the value of the return expression and done
set to true
.
The fourth call returns an object with value
set to undefined
and done
set to true
, indicating the function has completed execution.
Methods of the Iterator Object Returned by the Function
next Method
When next
is called without parameters, the return value of yield
is undefined
. When next
is called with a parameter, that parameter becomes the return value of the previous yield
.
function* sendParameter(){
console.log("start");
var x = yield '2';
console.log("one:" + x);
var y = yield '3';
console.log("two:" + y);
console.log("total:" + (x + y));
}
Without parameters:
var sendp1 = sendParameter();
sendp1.next();
// start
// {value: "2", done: false}
sendp1.next();
// one:undefined
// {value: "3", done: false}
sendp1.next();
// two:undefined
// total:NaN
// {value: undefined, done: true}
With parameters:
var sendp2 = sendParameter();
sendp2.next(10);
// start
// {value: "2", done: false}
sendp2.next(20);
// one:20
// {value: "3", done: false}
sendp2.next(30);
// two:30
// total:50
// {value: undefined, done: true}
return Method
The return
method returns a given value and terminates the iteration of the Generator function.
If a parameter is provided to return
, it is returned; otherwise, undefined
is returned.
function* foo(){
yield 1;
yield 2;
yield 3;
}
var f = foo();
f.next();
// {value: 1, done: false}
f.return("foo");
// {value: "foo", done: true}
f.next();
// {value: undefined, done: true}
throw Method
The throw
method can throw an exception outside the Generator function, which can be caught inside the function.
var g = function* () {
try {
yield;
} catch (e) {
console.log('catch inner', e);
}
};
var i = g();
i.next();
try {
i.throw('a');
i.throw('b');
} catch (e) {
console.log('catch outside', e);
}
// catch inner a
// catch outside b
yield* Expression
The yield*
expression is used to yield an iterator object, allowing one Generator function to call another within its body.
function* callee() {
console.log('callee: ' + (yield));
}
function* caller() {
while (true) {
yield* callee();
}
}
const callerObj = caller();
callerObj.next();
// {value: undefined, done: false}
callerObj.next("a");
// callee: a
// {value: undefined, done: false}
callerObj.next("b");
// callee: b
// {value: undefined, done: false}
// Equivalent to
function* caller() {
while (true) {
for (var value of callee) {
yield value;
}
}
}
Use Cases
Implementing Iterator
Providing iteration methods for objects that do not natively support the Iterator interface.
function* objectEntries(obj) {
const propKeys = Reflect.ownKeys(obj);
for (const propKey of propKeys) {
yield [propKey, obj[propKey]];
}
}
const jane = { first: 'Jane', last: 'Doe' };
for (const [key,value] of objectEntries(jane)) {
console.log(`${key}: ${value}`);
}
// first: Jane
// last: Doe
Reflect.ownKeys()
returns all properties of an object, including non-enumerable properties and Symbols.
The jane
object does not natively support the Iterator interface and cannot be iterated using for...of
. By using a Generator function, we add the Iterator interface to jane
, enabling iteration.
** Share Your Notes
-
-
-
-2.2 ES6 Destructuring Assignment
- 5.2 ES6 Generator Function
Follow on WeChat
English: