Notice when young lingyunzhi, has made the world first-class. Pay attention to avoid getting lost! It is said that like + favorites == learn


The concept of a Generator

The ES6 generator standard uses Python’s generator concept and syntax. If you are familiar with Python’s generator, then ES6’s generator is no problem.

Let’s review the concept of functions. A function is a complete piece of code. Calling a function takes arguments and returns the result:

function foo(x) {
    return x + x;
}

var r = foo(1); // Call foo
Copy the code

If there is no return statement at the end of the function, it is implied that return undefined; Control cannot be returned to the called code.

Generator is a new data type introduced by the ES6 standard. A generator looks like a function but can return multiple times. Executing Generator returns an iterator object. That is, a Generator function is a function that generates an iterator object.

ES6 provides a solution to asynchronous programming. 2. The cenerator is a state machine that encapsulates data in different states. 3. Each time you return the result of the expression after yield

Features:

Function (); function (); function (); function ();

function* foo(){
    let result = yield 'hello';// The status value is hello
    yield 'generator';// The status value is generator
}
Copy the code

A generator returns a pointer (iterator) and does not execute two internal logic. The next function returns {value: 5. The next method is called again from the yield at which it was last stopped until the end. 6. The yield statement usually returns undefined, and when the next method is called the contents of the parameter are used as the yield statement at start

Create a Generator

The way functions are declared

A generator, like a function, is defined as follows:

function* foo(x) {
    yield x + 1;
    yield x + 2;
    return x + 3;
}
Copy the code

Unlike functions, generator is defined by function* (note the extra *), has an asterisk * between the keyword function and the function name, and can be returned multiple times using yield in addition to a return statement.

The yield keyword can only be used in generator functions, otherwise an error will be reported

The way a function is expressed

Create generators in addition to function declarations; There are also ways to create generators using function expressions:

let foo = function* (arr) {
    for (let i = 0; i < arr.length; i++) {
        yieldarr[i]; }}let g = foo([1.2.3]);

console.log(g.next()); // {value: 1, done: false}
console.log(g.next()); // {value: 2, done: false}
console.log(g.next()); // {value: 3, done: false}
console.log(g.next()); // {value: undefined, done: true}
Copy the code

This is an anonymous function expression, so the * is between the function keyword and the parentheses

Note: you can’t create a generator using the arrow function, because you don’t know where to write it, do you

ES6 short for object methods

Generators can also be created using shorthand for ES6 object methods, by adding an asterisk * before the function name

let obj = {
    * createIterator(arr) {
        for (let i = 0; i < arr.length; i++) {
            yieldarr[i]; }}};Copy the code

How generators are invoked

1. The cycle:

Here you’ll find the normal for loop and for.. In loops are not appropriate, so use for.. The “of” loop does not iterate after the return

function* foo() {
    yield "a";
    yield "b";
    return 'c';
}
let g1 = foo();

for (let val of g1) {
    console.log(val); // a b
}
Copy the code

2. Deconstruction :(does not iterate after return)

function* foo() {
    yield "a";
    yield "b";
    return 'c';
};
let [g1, g2, g3] = foo();
console.log(g1, g2, g3); // a b undefined
Copy the code

3. Extended operator :(does not iterate after return)

function* show() {
    yield "a";
    yield "b";
    return 'c';
};
let [...g1] = show();
console.log(g1); // ["a", "b"]
Copy the code

4.Array.from() :(does not iterate after return)

function* show() {
    yield "a";
    yield "b";
    return 'c';
};
let g1 = Array.from(show());
console.log(g1); // ["a", "b"]
Copy the code

5. Object generator methods:

Generators are functions themselves and can be added to objects as methods of objects

let obj = {
    createIterator: function* (arr) {
        for (let i = 0; i < arr.length; i++) {
            yieldarr[i]; }}};let iterator = obj.createIterator([10.20.30]);
console.log(iterator.next()); // {value: 10, done: false}
console.log(iterator.next()); // {value: 20, done: false}
console.log(iterator.next()); // {value: 30, done: false}
console.log(iterator.next()); // {value: undefined, done: true}
Copy the code

Generator returns multiple functions

Generator is a “function” that can return multiple times? What’s the use of going back multiple times?

Let’s take a famous Fibonacci number that starts with 0,1:

0 1 1 2 3 5 8 13 21 34.Copy the code

To write a function that produces the Fibonacci sequence, write:

function fib(max) {
    var
        t,
        a = 0,
        b = 1,
        arr = [0.1];
    while (arr.length < max) {
        [a, b] = [b, a + b];
        arr.push(b);
    }
    return arr;
}

/ / test:
fib(5); // [0, 1, 1, 2, 3]
fib(10); // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
Copy the code

The function can only return once, so it must return an Array. However, with generator, you can return one number at a time, many times over. Rewrite with generator as follows:

function* fib(max) {
    var
        t,
        a = 0,
        b = 1,
        n = 0;
    while (n < max) {
        yield a;
        [a, b] = [b, a + b];
        n ++;
    }
    return;
}
Copy the code

Try calling directly:

fib(5); // fib {[[GeneratorStatus]]: "suspended", [[GeneratorReceiver]]: Window}
Copy the code

Calling a generator directly is not the same as calling a function. Fib (5) simply creates a generator object and does not execute it.

There are two ways to call a Generator object. One is to call the next() method of the generator object repeatedly:

var f = fib(5);
f.next(); // {value: 0, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 2, done: false}
f.next(); // {value: 3, done: false}
f.next(); // {value: undefined, done: true}
Copy the code

The next() method executes generator code, and yield x each time it encounters it; Return an object {value: x, done: true/false} and “pause”. The value returned is yield, and done indicates whether the generator has finished executing. If done is true, value is the return value of return.

When done is true, the generator object is complete, do not continue calling next().

The second method is to directly use for… The of loop iterates over the generator object in a way that doesn’t require our own judgment done:

'use strict'

function* fib(max) {
    var
        t,
        a = 0,
        b = 1,
        n = 0;
    while (n < max) {
        yield a;
        [a, b] = [b, a + b];
        n ++;
    }
    return;
}

// Use the 'for' loop to batch process the 'yield' statements
for (var x of fib(10)) {
    console.log(x); // Output 0, 1, 1, 2, 3...
}
Copy the code

What does a generator do compared to a normal function?

Because the generator can return multiple times during execution, it looks like a function that remembers the state of execution, and writing a generator can take advantage of this by performing functions that require object orientation. For example, to use an object to hold state, write:

var fib = {
    a: 0.b: 1.n: 0.max: 5.next: function () {
        var
            r = this.a,
            t = this.a + this.b;
        this.a = this.b;
        this.b = t;
        if (this.n < this.max) {
            this.n ++;
            return r;
        } else {
            return undefined; }}};Copy the code

Using an object’s properties to store state is tedious.

Generator also has the great benefit of turning asynchronous callback code into “synchronous” code. This benefit won’t be realized until you learn AJAX later.

In the dark ages before the Generator, AJAX code was written like this:

ajax('http://url-1', data1, function (err, result) {
    if (err) {
        return handle(err);
    }
    ajax('http://url-2', data2, function (err, result) {
        if (err) {
            return handle(err);
        }
        ajax('http://url-3', data3, function (err, result) {
            if (err) {
                return handle(err);
            }
            return success(result);
        });
    });
});
Copy the code

The more callbacks, the uglier the code.

In the good old days with Generators, you could write something like this when using AJAX:

try {
    r1 = yield ajax('http://url-1', data1);
    r2 = yield ajax('http://url-2', data2);
    r3 = yield ajax('http://url-3', data3);
    success(r3);
}
catch (err) {
    handle(err);
}
Copy the code

Code that looks synchronous is actually executed asynchronously.

The completeajaxThe request instance

function ajax(url) {
    return new Promise((resolve, reject) = > {
        $.ajax({
            url,
            type: 'get'.success: resolve,
            error: reject
        });
    });
}

function* show() {
    yield ajax('https://jsonplacehouger.typicode.com/todos/1');
    yield ajax('https://jsonplacehouger.typicode.com/todos/2');
    yield ajax('https://jsonplacehouger.typicode.com/todos/3');
};

let g1 = show();

g1.next().value.then(res= > {
    console.log(res);
    return g1.next().value;
}).then(res= > {
    console.log(res);
    return g1.next().value;
}).then(res= > {
    console.log(res);
    return g1.next().value;
});
Copy the code

╭ ╮ ╱ ╭ ┳ ━ ━ ━ ┳ ╮ ╱ ╭ ╮ ┃ ┃ ╱ ┃ ┃ ╭ ━ ╮ ┃ ┃ ╱ ┃ ┃ ┃ ╰ ━ ╯ ┃ ┃ ┃ ┃ ┃ ╰ ━ ╯ ┃ ╰ ━ ━ ╮ ┃ ┃ ┃ ┃ ┣ ━ ━ ╮ ┃ ╱ ╱ ╱ ┃ ┃ ╰ ━ ╯ ┃ ╱ ╱ ┃ ┃

It is said that praise + collection == learn