It should be noted that when I was young, lingyunzhi , Once the best in the world . Pay attention to prevent getting lost ! It is said that give the thumbs-up + Collection == Learn to
ES6 Definition generator Standard guys learn from Python Of generator The concept and grammar of , If you are right about Python Of generator Familiar with , that ES6 Of generator Naturally .
Let's review the concept of function first . A function is a complete piece of code , To call a function is to pass in parameters , And then return the result :
function foo(x) {
return x + x;
}
var r = foo(1); // call foo function
Copy code
Function in execution , If I don't meet return
sentence ( If there is no at the end of the function return
, It's implicit return undefined;
), Control cannot be returned to the called code .
generator( generator ) yes ES6 New data types introduced by the standard . One generator It looks like a function , But you can go back many times . perform Generator The function returns an iterator object . That is to say ,Generator Function is a function that generates an iterator object .
1、ES6 Provides a solution to asynchronous programming
2、cenerator The number of is a state machine , It encapsulates data in different states
3、 Used to generate the traverser object
4、 Pause function ( Lazy evaluation ),yield Can pause ,next Method can start . Every time I return yield The result of the expression after
characteristic :
1、function There is an asterisk between and the function name
2、 For internal use yield Expressions to define different states
for example :
function* foo(){
let result = yield 'hello';// The status value is hello
yield 'generator';// The status value is generator
}
Copy code
3、generator The function returns a pointer object ( Press 11 In Chapter iterator), Instead of executing the internal logic of two numbers
4、 call next The internal logic of the method function begins to execute , encounter yield The expression stops , return {value:yield The expression after
5、 Call again next The method will start from the last stop yield Start at , Until the last
6、yield The return result of the statement is usually undefined, When calling next Method will be used as the start time yield sentence
generator It's like a function , The definition is as follows :
function* foo(x) {
yield x + 1;
yield x + 2;
return x + 3;
}
Copy code
generator Unlike functions ,generator from function*
Definition ( Pay attention to the extra *
Number ), keyword function
And Function name
There is an asterisk between *
, also , except return
sentence , You can also use yield
Go back many times .
yield
Keywords can only be used in generators generator
Use in a function , Otherwise, an error will be reported
except Function declaration To create a generator ; also Function expression To create a generator :
let foo = function* (arr) {
for (let i = 0; i < arr.length; i++) {
yield arr[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 code
This is an anonymous function expression , therefore * stay function Between keywords and parentheses
Be careful : You cannot create a generator through an arrow function , After all * I don't know where to write, do I
It can also be used. ES6 Object method to create a generator , Just add an asterisk before the function name *
let obj = {
* createIterator(arr) {
for (let i = 0; i < arr.length; i++) {
yield arr[i];
}
}
};
Copy code
Here we will find , ordinary for Circulation and for..in Cycles are not appropriate , So use for..of loop Not traverse return Later
function* foo() {
yield "a";
yield "b";
return 'c';
}
let g1 = foo();
for (let val of g1) {
console.log(val); // a b
}
Copy code
function* foo() {
yield "a";
yield "b";
return 'c';
};
let [g1, g2, g3] = foo();
console.log(g1, g2, g3); // a b undefined
Copy code
function* show() {
yield "a";
yield "b";
return 'c';
};
let [...g1] = show();
console.log(g1); // ["a", "b"]
Copy code
function* show() {
yield "a";
yield "b";
return 'c';
};
let g1 = Array.from(show());
console.log(g1); // ["a", "b"]
Copy code
The generator itself is a function , So it can be added to the object , The method of becoming an object
let obj = {
createIterator: function* (arr) {
for (let i = 0; i < arr.length; i++) {
yield arr[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 code
generator Can return multiple times “ function ”? What's the use of returning multiple times ?
Let's take a famous Fibonacci sequence as an example , It consists of 0
,1
start :
0 1 1 2 3 5 8 13 21 34 ...
Copy code
To write a function that produces a Fibonacci sequence , It can be written like this :
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 code
Function can only return once , So you have to return a Array
. however , If replaced generator, You can return one number at a time , Go back and forth many times . use generator Rewrite 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 code
Try calling directly :
fib(5); // fib {[[GeneratorStatus]]: "suspended", [[GeneratorReceiver]]: Window}
Copy code
Call one directly generator Unlike calling a function ,fib(5)
Just created a generator object , Haven't implemented it yet .
call generator There are two ways to object , One is to constantly call generator Object's next()
Method :
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 code
next()
Method will execute generator Code for , then , Every encounter yield x;
Just return an object {value: x, done: true/false}
, then “ Pause ”. Back to value
Namely yield
The return value of ,done
Express this generator Whether the execution is over . If done
by true
, be value
Namely return
The return value of .
When executed done
by true
when , This generator The object has been executed , Don't call on next()
了 .
The second method is to use for ... of
Loop iteration generator object , This approach does not 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;
}
// adopt `for` loop , Batch processing `yield` sentence
for (var x of fib(10)) {
console.log(x); // Output... In sequence 0, 1, 1, 2, 3, ...
}
Copy code
because generator You can return... Multiple times during execution , So it looks like a function that can remember the execution state , Take advantage of this , Write a generator You can realize the functions that can only be realized with object-oriented . for example , Use an object to save the State , That's how it's written :
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 code
Use the properties of the object to save the State , Quite complicated .
generator There is another great benefit , It is to change the asynchronous callback code into “ Sync ” Code . This benefit will have to be learned later AJAX Only later can we realize .
No, generator The dark ages before , use AJAX You need to write code 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 code
More callbacks , The more ugly the code is .
With generator A better time , use AJAX It can be written like this :
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 code
Looks like synchronized code , The actual execution is asynchronous .
ajax
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 code
╭╮╱╭┳━━━┳╮╱╭╮
┃┃╱┃┃╭━╮┃┃╱┃┃
┃╰━╯┃┃┃┃┃╰━╯┃
╰━━╮┃┃┃┃┣━━╮┃
╱╱╱┃┃╰━╯┃╱╱┃┃
When you come, you can't go until you like it , It is said that give the thumbs-up + Collection == Learn to