• Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.

What is a generator?

Generators are an extremely flexible addition to ECMAScript 6, with the ability to pause and resume code execution within a function block.

2. Declaration of generator functions

The form of a generator is a function whose name is preceded by an asterisk (*) to indicate that it is a generator. Wherever you can define a function, you can define a generator. Function *show() {} let show = function* () {} let person = {*show() {} Class Person {*show() {}} // Declare class Person {static *show() {}} // Note: arrow functions cannot be used to define generator functionsCopy the code

3. Basic use of generator functions

Calling a generator function produces a generator object. // The generator object is initially paused. // Generator objects implement the Iterator interface and therefore have the next() method. // Calling the next() method causes the generator to start or resume execution. The next() method returns a value similar to an iterator, with a done attribute and a value attribute. Generator functions with an empty body do not stop in the middle; a call to next() will bring the generator to the done: true state. function* eat() { } const generator = eat(); console.log(generator.next()); //{ value: undefined, done: Function * hello() {return 'hello Generator!!! '; } const generator = hello(); console.log(generator.next()); // { valeue: "Hello Generator !!!" // Generator objects implement the Iterable interface, and their default iterators are self-referentialCopy the code

4. Use yield to interrupt execution

  • The yield keyword allows the generator to stop and start execution, and is where the generator is most useful.
  • The generator function executes normally until the yield keyword is encountered.
  • Once the yield keyword is encountered, the execution is stopped and the state of the function’s scope is preserved.
  • A stopped generator function can only be resumed by calling the next() method on the generator object.
// The yield keyword is a bit like the intermediate return statement of a function, producing the value that will appear in the object returned by the next() method. // A generator function that exits with yield will be in the done: false state. // Exit generator functions with the return keyword in the done: true state. Function * eat() {yield" ; Yield "Lunch!" ; Return 'rest! '; Yield "Dinner at night!" ; } const generator = eat(); console.log(generator.next()); // {value: "breakfast!" , done: false } console.log(generator.next()); // {value: "lunch!" , done: false } console.log(generator.next()); // {value: "rest!" , done: true } console.log(generator.next()); // {value: undefined, done: true} // Note: // the execution flow of the content part of the generator function is scoped for each generator object. // Calling next() on one generator object does not affect other generators. // The yield keyword can only be used inside a generator function and will throw an error if used elsewhere. Function * hello() {function item() {yield; function* hello() {yield; } } const generator = hello(); generator.next(); // This is invalidCopy the code

5. Generator objects can be used as iterators

// Because generator objects implement the Iterable interface, and because both generator functions and default iterators are called to produce iterators, generators are particularly suitable as default iterators. // Example: function* hello() {yield 'morning '; Yield C. Yield C. } for (let value of hello()) { console.log(value); } // Print the result: // morning // noon // eveningCopy the code

6. Use yield to implement input and output

In addition to being used as an intermediate return statement of a function, the yield keyword can also be used as an intermediate argument to a function. Function * hello(value) {console.log(value); // The value passed in by the first call to next() will not be used, because this call is to start execution of the generator function function* hello(value) {console.log(value); console.log(yield); console.log(yield); console.log(yield); } const generator = hello(' morning '); Generator.next (' the value here will not be used '); The generator. The next (' noon '); The generator. The next (' night '); Function * hello(value) {return yield 'hello'; } const generator = hello(); console.log(generator.next()); // { value: "hello", done: false } console.log(generator.next('Generator')); // { value: "Generator", done: True} // Since the function must evaluate the entire expression to determine the value to return, // it pauses execution when it hits the yield keyword and evaluates the value to produce // The next call to next() passes in a value as the value to be given to the same yield. // This value is then determined as the value to be returned by the generator functionCopy the code

7. Generate iterables

Function * generatorFunc(value) {yield* [1, 2, 3]; function* generatorFunc(value) {yield* [1, 2, 3]; } const generator = generatorFunc(); console.log(generator.next()); // {value: 1, done: false} console.log(generator.next()); // {value: 2, done: false} console.log(generator.next()); // {value: 3, done: false} // Because yield* actually serializes an iterable into a sequence of values that can be produced individually, this is no different from putting yield into a loop.Copy the code

8. Kill the generator early

// Like iterators, generators support the concept of "closeable". // An object that implements the Iterable interface must have a next() method and an optional return() method to prematurely terminate the iterator. In addition to these two methods, generator objects have a third method: the throw() // return() and throw() methods can both be used to force the generator into a closed state. 1. The return() // return() method forces the generator into a closed state. function* generatorFunc(value) { yield* [1, 2, 3]; } const generator = generatorFunc(); console.log(generator.next()); // { value: 1, done: false } console.log(generator.return()); // { value: undefined, done: true } console.log(generator.next()); // Unlike iterators, all generator objects have a return() method // once it enters the closed state, it cannot be recovered. // A subsequent call to next() displays the done: true state, and any returned value provided is not stored or propagated. 2. The throw() // throw() method injects a supplied error into the generator object when paused. Function * generatorFunc(value) {yield 1; Try {throw new Error(' Error '); } catch (err) { console.log(err); } yield 2; } const generator = generatorFunc(); console.log(generator.next()); console.log(generator.next()); // However, if the generator function handles the error internally, the generator will not be shut down and execution can resume. // Error handling skips the corresponding yield, so in this case a value will be skipped.Copy the code

\