Generator function in ES6

1. Generator introduction

Declaration: The Generator function is an asynchronous programming solution provided by ES6. It can be regarded as a state machine that encapsulates multiple internal states. Executing the Generator function will return a traverser object, so it is also a traverser object generation function. The Generator function is also an ordinary function, but it has two characteristics. The first is that there is an * between the funtction keyword and the function name, and the second is that the yield expression is used inside the function body to define different internal states.

 function* fun() {
            yield "张三"  //状态1
            yield "李四"  //状态2
            return "结束" //状态3
        }
        const obj = fun()
        console.log(obj); //fun {<suspended>}

Declaration: What is returned is a pointer object pointing to the internal state, that is, the traverser object.

2. The Generator function is executed in segments

Declaration: The Generator function is executed in segments, the yield expression is a marker to suspend execution, and the next method can resume execution.

   console.log(obj.next()); //{value: '张三', done: false}
        console.log(obj.next()); //{value: '李四', done: false}
        console.log(obj.next()); //{value: '结束', done: true}
        // 第三次调用Generator函数从上次yield表达式停下的地方,一直执行到下一个yield表达式。如果有retrun就执行到retrun
        console.log(obj.next()); //{value: undefined, done: true}

3. yield expression

Statement: An expression that can suspend the flag of the function. Only when the next() method is called, the internal pointer points to the statement. We can regard it as a syntactic function of lazy evaluation.

  function* fun2(a, b) {
            yield a + b
            return a * 5
        }
        const obj2 = fun2(5, 6)
        console.log(obj2); //fun2 {<suspended>}
        console.log(obj2.next()); //{value: 11, done: false}
        console.log(obj2.next()); //{value: 25, done: true}
        console.log(obj2.return(5)); //{value: 5, done: true}

Note: The difference between return and yield, there can only be one return statement in a function.

4. Special form

 Explanation: The Genrator function does not need the yield expression, and then it becomes a purely deferred execution function.

 function* fun3() {
            console.log("Hello world");
        }
        console.log(fun3().next());
        //Hello world
        //{value: undefined, done: true}

5.yield express attention points

  1. The yield expression can only be used in the Generator function.
  2. A yield expression must be enclosed in parentheses if it is used within another expression.
 function* fun4() {
            console.log("你好" + (yield 123));
            console.log("你好" + (yield 234));
        }
        const obj4 = fun4()
        console.log(obj4.next()); //{value: 123, done: false}
        console.log(obj4.next()); //{value: 234, done: false}

6. Relationship with Iterator interface

Explanation: Since the Generator function is an iterator generation function, you can assign Geneartor to the Symbol.iterator property of the object, so that the object has an Iterator interface.

  const myIter = {}
        myIter[Symbol.iterator] = function* fun5() {
            yield 1
            yield 2
            return 3
        }
        console.log(...myIter);
        //1 2 

 Explanation: If there is no result of 3, it means that only the expression declared by yield will be traversed. (Because the done property of the returned object is true, the for...of loop will abort)

7. The generator function is the traverser function

const fun6 = function* () {

        }
        const newFun6 = fun6()
        console.log(newFun6 === newFun6[Symbol.iterator]()); //true

8. Parameters of the next method

Explanation: The next method can take a parameter, which will be used as the return value of a yield expression.

 function* fun7(x) {
            let a = 4 * (yield (x + 1))
            let b = yield (a / 3)
            return (a + b + x)
        }
        const obj5 = fun7(1)
        console.log(obj5.next()); //{value: 2, done: false}
        console.log(obj5.next()); //{value: NaN, done: false}
        console.log(obj5.next()); //{value: NaN, done: true}
        // 第二次运行next()方法的时候不带参数,导致4*undefined等于NaN

        const obj6 = fun7(2)
        console.log(obj6.next()); //{value: 3, done: false}
        console.log(obj6.next(2)); //{value: 2.6666666666666665, done: false}
        console.log(obj6.next(3)); //{value: 13, done: true}

Explanation: The parameters of the next method represent the return value of the previous yield expression, so the first time the next method is used, no parameters are required. The v8 engine directly ignores the first use of the next() method, and only the second use of the next() method starts, and the parameters are still valid.

9. for...of loop

Note: The for...of loop can automatically traverse the Iterator object generated by the Genrator function at runtime, and it is no longer necessary to call the next() method at this time.

     function* fun8() {
            yield 1
            yield 2
            yield 3
            return 4
        }
        for (let i of fun8()) {
            console.log(i);
            //1
            //2
            //3
        }

Note: The return is not traversed because the done property of the returned object is true, the for...of loop will be terminated, and the returned object will not be included.

10.Generator.prototype.throw

Explanation: The traverser object returned by the Generator function can have a throw method, which can be captured in the body of the function Generartor function.

    const fun9 = function* () {
            try {
                yield
            } catch (error) {
                console.log("内部捕获", error);
            }
        }
        const obj8 = fun9()
        obj8.next()
        try {
            obj8.throw("错误1")
            obj8.throw("错误2")
        } catch (error) {
            console.log("外部捕获", error);
        }
        //内部捕获 错误1
        //外部捕获 错误2

Explanation: Since the catch statement inside the Generator function has been executed, this error will not be caught, and then the Generator function body is thrown.

11.Genrator.prototype.return

Description: The traverser function returned by the Generator function also has a return method, which can return a specified value and terminate the Generator function.

     function* fun10() {
            yield 1
            yield 2
        }
        const obj10 = fun10()
        console.log(obj10.next()); //{value: 1, done: false}
        console.log(obj10.return(10));//{value: 10, done: true}
        console.log(obj10.next()); //{value: undefined, done: true}

12.try...finally

Explanation: Use the try...finally code block, and the try code block is being executed, then the return() method will immediately enter the finally code block, and the entire function will end after execution.

  function* fun11() {
            try {
                yield 1
                yield 2
            } finally {
                yield 10
                yield 20
            }
        }
        const obj11 = fun11()
        console.log(obj11.next()); //1
        console.log(obj11.return(10)); //{value: 10, done: false}
        console.log(obj11.next()); //{value: 20, done: false}

13. next(), throw(), return() common

Description: In fact, the Generator function resumes execution when it works, and replaces the yield expression with a different statement.

14. yield* expression

Description: Solve the problem of executing another Generator function inside the Generator function.

 function* fun12() {
            yield 2
            yield 3
        }
        function* fun13() {
            yield 4
            yield* fun12()
            yield 5
        }
        //    等价于
        function* fun13() {
            yield 4
            yield 2
            yield 3
            yield 5

        }

15. Generator function of object properties

Note: If the property of the object is a Generator function, it can be abbreviated as the following form.

  const obj12 = {
            *fun14() {

            }
        }

16. This of the Generator function

Explanation: Because the Generator function always returns a traverser, it is an instance of the Generator function. To change the point of this can be modified through the call method, apply method, etc.

   function* fun15() {
            this.a = 666
            yield 1

        }
        const obj14 = {
     
        }
        const obj15 = fun15()
        obj15.next()
        console.log(obj15.a); //undefined
        // 改变this
        const obj16 = fun15.call(obj14)
        console.log(obj16.next());//{value: 1, done: false}
        console.log(obj14.a);

Note: After the constructor is called, this empty object is the instance object of the Generator function.

Guess you like

Origin blog.csdn.net/m0_62785037/article/details/130779082