Generator functions are an asynchronous programming solution provided by ES6.

Asynchronous programming

  1. The so-called asynchronous, is a task divided into two parts, first perform one part, then switch to the other task, and then go back to the second part

  2. Asynchronous programming

  • The callback function
  • Event listeners
  • Publisher/subscriber
  • Promise object
  1. The so-called callback function is to write the second paragraph in a separate function that is called when the task is to be executed again

The asynchronous method of callback functions is easy to form multiple nesting. Multiple asynchronous operations form a strong coupling. Whenever an operation needs to be modified, its upper and lower callback functions need to be modified. This situation is called callback hell

What is a Generation

Syntactically, the Generator function is understood to be a state machine that encapsulates multiple internal states.

Formally, a Generator function is an ordinary function

The entire Generator function is an encapsulated asynchronous task, or a container for asynchronous tasks, and uses yield statements whenever asynchronous operations need to be paused

Features of generator functions:

(1) There is an asterisk * between the function keyword and the function, and internal use yield expression, define different internal state

(2) After invoking the Generator function, the function does not execute and returns a pointer object to the internal state rather than the result of the function’s operation

Defining Generator functions

function* fn(){   // Define a Generator function
    yield 'hello';
    yield 'world';
    return 'end';
}
var f1 =fn();           // Call Generator, which returns a pointer to the internal state
console.log(f1);        // fn {[[GeneratorStatus]]: "suspended"}
console.log(f1.next()); // {value: "hello", done: false}
console.log(f1.next()); // {value: "world", done: false}
console.log(f1.next()); // {value: "end", done: true}
console.log(f1.next()); // {value: undefined, done: true}
Copy the code

However, when a Generator function is called, it does not execute and returns not the result of the function’s execution, but a pointer object to the internal state.

Next, the next method of the traverser object must be called to move the pointer to the next state. That is, each time the next method is called, the internal pointer executes from the head of the function or where it was last stopped until the next yield expression (or return statement) is encountered.

The Generator functions are executed piecewise, the yield expression is a token to pause execution, and the next method can resume execution.

The pause effect of Generator functions means that asynchronous operations can be written in yield statements and executed later when the next method is called. This is essentially equivalent to not having to write the callback function, because subsequent operations of the asynchronous operation can be put under the yield statement until the next method is called anyway. Therefore, an important practical use of Generator functions is to handle asynchronous operations and override callback functions.

Yield expressions and next() methods

The Generator returns an iterator object that only calls the next method through the next internal state, so it provides a function to pause execution.

The yield expression is the pause flag.

The expression following the yield expression is executed only when the next method is called and an internal pointer points to the statement.

Use yield to note:

(1) The yield statement can only be used in the scope of function*. If function* defines other ordinary functions inside, the yield statement is not allowed inside the function.

(2) If the yield statement participates in an operation, it must be enclosed in parentheses.

The difference between the return method and the next method:

1) Return terminates iteration, and all subsequent yield statements are invalidated; Next returns the return value of this yield statement. 2)return {value: undefined, done: true}; Next returns the yield statement if there are no arguments. Return {value: argument, done: true}; When next has arguments, it overwrites the return value of the last yield statement, which may or may not be related to the argument (if the argument is evaluated).Copy the code

The next method running logic for the traverser object:

(1) When a yield expression is encountered, the following operation is paused, and the value immediately following the yield expression is used as the value of the returned object's value property. (2) The next time the next method is called, the execution continues until the next yield expression is encountered. (3) If no new yield expression is encountered, the function is run until the end of the return statement, and the value of the expression following the return statement is used as the value of the returned object's value property. (4) If the function does not have a return statement, the value attribute of the returned object is undefined.Copy the code

Such as:

function* fn(){   // Define a Generator function
    yield 'hello';
    yield 'world';
}
var f1 =fn();           // Call the Generator function
console.log(f1);        // fn {[[GeneratorStatus]]: "suspended"}
console.log(f1.next()); // {value: "hello", done: false}
console.log(f1.next()); // {value: "world", done: false}
console.log(f1.next()); // {value: undefined, done: true}
Copy the code
function* fn(){   // Define a Generator function
    yield 'hello';
    yield 'world';
    return 'end';
}
var f1 =fn();           // Call the Generator function
console.log(f1);        // fn {[[GeneratorStatus]]: "suspended"}
console.log(f1.next()); // {value: "hello", done: false}
console.log(f1.next()); // {value: "world", done: false}
console.log(f1.next()); // {value: "end", done: true}
Copy the code

Next () method argument

Represents the return value of the previous yield expression, so the passing argument is invalid the first time the next method is used. The V8 engine ignores arguments from the first use of the next method, which are valid only from the second use of the next method. Semantically, the first next method is used to start the traverser object, so it doesn’t take arguments.

for… of… cycle

Iterator objects generated during Generator functions can be iterated automatically, and the next method is no longer required. Once the done property of the object returned by the next method is true, for… The of loop terminates and does not contain the return object.