ES6 introduced Generator functions, which can suspend the execution flow of a function through the `yield` keyword, making it possible to change the execution flow and thus providing a solution for asynchronous programming. Basic Usage
Generator Function Composition
Generator has two parts that distinguish it from ordinary functions:
-
One is that after `function` and before the function name, there is a `*`;
-
Inside the function there is a `yield` expression.
Among them, `*` is used to indicate that the function is a Generator function, and `yield` is used to define the internal state of the function.
Execution Mechanism
Calling a Generator function is the same as calling a regular function: just add parentheses after the function name. However, a Generator function does not execute immediately like a regular function; instead, it returns a pointer to an internal state object. Therefore, to call the `next` method of the iterator object, the pointer will start executing from the beginning of the function or from where it last stopped.
When calling the `next` method for the first time, execution starts from the beginning of the Generator function. First it prints `one`, then stops when reaching `yield`, and uses the value of the expression after `yield`, `'1'`, as the `value` property of the returned object. At this point the function has not finished executing, so the `done` property of the returned object is `false`.
When calling the `next` method for the second time, it is the same as the previous step.
When calling the `next` method for the third time, it first prints `three`, then performs the function's return operation, and uses the value of the expression after `return` as the `value` property of the returned object. At this point the function has ended, so the `done` property value is `true`.
When calling the `next` method for the fourth time, the function has already finished executing, so it returns `undefined` as the `value` property value and `true` as the `done` property value. If there were no `return` statement during the third step, it would directly return `{value: undefined, done: true}`.
Methods of the Iterator Object Returned by the Function
`next` method
In general, when the `next` method is called without arguments, the return value of the `yield` expression is `undefined`. When `next` is passed an argument, that argument will serve as the return value of the previous `yield`.
Calling `next` without arguments
In addition to using `next`, you can also use a `for...of` loop to iterate over the Iterator object generated by a Generator function.
`return` method
The `return` method returns the given value and ends iteration of the Generator function.
When the `return` method is provided with an argument, it returns that argument; when no argument is provided, it returns `undefined`.
The iterator object throws two errors. The first one is caught inside the Generator function. The second one, because the `catch` inside the function body has already executed, will not be caught again, so this error is thrown out of the Generator function body and caught by the `catch` outside the function body.
`yield*` expression
The `yield*` expression means that `yield` returns an iterator object, which is used to call another Generator function inside a Generator function.
Use Cases
Implementing Iterator
Provides a traversal method for objects that do not have an Iterator interface.
`Reflect.ownKeys()` returns all properties of an object, regardless of whether the properties are enumerable, including Symbols.
`jane` natively does not have an Iterator interface and cannot be traversed with `for...of`. Here, a Generator function is used to add an Iterator interface, so the `jane` object can be traversed.