Generator function and yield

Generator function and yield in ES6

The generator function is a function that solves asynchronous programming. The generator function returns an iterable object (that is, a traversable object).
Formally, the Generator function declaration method is quite similar to that of an ordinary function, but it has two characteristics. First, there is an asterisk between the function keyword and the function name; second, the yield expression is used inside the function body to define different internal states (yield means “output” in English).

function* num() {<!-- -->
yield "111";
yield "222";
yield "333";
}
const iterator = num();
// console.log(iterator.next());
// console.log(iterator.next());
// console.log(iterator.next());
// console.log(iterator.next());
/*
        As a result of the execution of the above code, the generator function is for asynchronous operations and will not be executed synchronously.
        The code is separated by yield. The separated code blocks are: the number of yield + 1. The generator function will not automatically execute itself, but needs to call the next method to execute it.
        Calling the next() method will generate a pointer. The first next() method executes the first yield. When the second yield is called, the pointer will move to the second yield to traverse the generator function.
        The generator function will return an iterator object, then we can traverse it through for of
        {value: '111', done: false}
        {value: '222', done: false}
        {value: '333', done: false}
        {value: undefined, done: true}
        */

for (const v of iterator) {<!-- -->
// console.log('Traverse each item of generator: ', v);
}
/*
        As a result of the above code traversal, each item traversed is the value of the value in the object returned after calling the next()n method, which is the value after yield.
            Traverse each item of generator: 111
            Traverse each item of generator: 222
            Traverse each item of generator: 333
        */

// Similarly, the generator function can pass parameters like a normal function, and the next() method can also pass parameters.
function* animal(args) {<!-- -->
console.log("Arguments received:", ...args);
yield "monkey";
yield "elephant";
yield "seal";
}
const animalGenerator = animal(["", "", "", ""]);
// If you just call the generator function, the function will not be executed. If you want to output the result, you must call the next() method.
animalGenerator.next();

// Pass parameters to next() method
function* phone() {<!-- -->
const res1 = yield "Huawei";
console.log(res1);
const res2 = yield "xiaomi";
console.log(res2);
const res3 = yield "oppo";
console.log(res3);
}
const phoneSort = phone();
phoneSort.next("aaa");
phoneSort.next("bbb");
phoneSort.next("ccc");
phoneSort.next("ddd");
/*
        The above code execution results:
        bbb
        ccc
        ddd
        It can be found that when we pass parameters to the next() method, four parameters are passed in but only 3 parameters are printed. This shows that when we pass parameters to the next() method, the parameters passed in will not be matched. The yield received
        Instead, it becomes the return value of the previous yield, so our res1 does not print aaa but bbb.
        */

// Compare yield and yield *
function* generatorOne() {<!-- -->
yield ["a", "b", "c"];
}

function* generatorTwo() {<!-- -->
// yield* ["a", "b", "c"];
                yield 'a'
                yield 'b'
                yield 'c'
}
            const one = generatorOne()
            const two = generatorTwo()
            console.log(one.next().value);
            console.log(two.next().value);
        /*
        Print results using yield*:
            ['a', 'b', 'c']
            a
        All print results using yield:
            ['a', 'b', 'c']
            a
        It can be found that the printing results of the two are exactly the same
        We can conclude: yield* ['a','b','c'] is equivalent to yield 'a'; yield 'b'; yield 'c';
        */


example:

 // What code should be entered in the English marked position below so that obj.next() will have the following content
//Example:
        const teams = [
            {<!-- -->name: 'Team 1', members: ['Paul', 'Lisa']},
            {<!-- -->name: 'Team 2', members: ['Laura', 'Tim']},
        ]
        //The generator function will return an iterable object
        function * getMembers(members) {<!-- -->
            for (let i = 0; i < members.length; i + + ) {<!-- -->
                yield members[i]
            }
        }
        function * getTeams(teams) {<!-- -->
            for (let i = 0; i< teams.length; i + + ) {<!-- -->
                // something is missing here
          }
        }
        const obj = getTeams(teams)

       obj.next() // {value: "Paul", done: false}
       obj.next() // {value: "Lisa", done: false}
const teams = [
            {<!-- -->name: 'Team 1', members: ['Paul', 'Lisa']},
            {<!-- -->name: 'Team 2', members: ['Laura', 'Tim']},
        ]
        //The generator function will return an iterable object
        function * getMembers(members) {<!-- -->
            for (let i = 0; i < members.length; i + + ) {<!-- -->
                yield members[i]
            }
        }
        function * getTeams(teams) {<!-- -->
            for (let i = 0; i< teams.length; i + + ) {<!-- -->
                // something is missing here
                yield* getMembers(teams[i].members)
                // console.log(getMembers(teams[i].members));
                // let iterator = getMembers(teams[i].members)
                //The iterable object returned by the first loop is equivalent to
                /*
                    yield 'Paul'
                    yield 'Lisa'
                */
                //The iterable object returned by the second loop is equivalent to
                /*
                    yield 'Laura'
                    yield 'Tim'
                */
                // So yield * getMembers(teams[i].members) is equivalent to
                /*
                    yield * ['Paul', 'Lisa', 'Laura', 'Tim']
                */
                for (const v of iterator) {<!-- -->
                    // console.log(v);
                }
                // Determine how many times this loop has been executed, whether it is executed synchronously or asynchronously
                // console.log(i);
            }
        }
        const obj = getTeams(teams)
        // The for of loop traverses the generator object: obj
        for (const item of obj) {<!-- -->
            console.log(item);
        }
        // obj.next() // {value: "Paul", done: false}
        // obj.next() // {value: "Lisa", done: false}

We found by printing that the getMembers() function returns a generator object every time, and the value inside is exactly the value in members in teams, so the final value is equivalent to

 yield * ['Paul', 'Lisa', 'Laura', 'Tim']