A lot of writing in the last two years Generator+co, Use it to write code similar to synchronization
But actually ,Generator It's not made for this , Otherwise, there will be no later asyncawait
Generator Is a function that can be suspended , And when to recover , It's up to the caller
I hope this article can help you understand Generator What is it , And how to use it

Show me a picture of Generator The understanding of the :

A coffee machine , Although I don't drink coffee , Unfortunately, we can't find a machine to make Wang Laoji -.-

What I understand Generator The coffee machine is like this :

  1. First , We put some coffee beans in the machine
  2. When we want coffee , You can press the switch (gen.next()), The machine starts to grind the coffee beans 、 The coffee 、 And then there's coffee
  3. After a full cup of coffee , The valve will close automatically (yield)
  4. If you put a lot of coffee beans in the machine at first , here , There will still be some left in the machine , Next time you want to drink, you can continue to press the switch , perform ( The bean grinding 、 The coffee 、 Pick up the coffee ) This set of operations

take Generator Let's realize the above coffee machine :

function * coffeeMachineGenerator (beans) {
do {
yield cookCoffee()
} while (--beans) // The coffee
function cookCoffee () {
console.log('cooking') return 'Here you are'
} // Put coffee beans in the coffee machine
let coffeeMachine = coffeeMachineGenerator(10) // I want to have coffee
coffeeMachine.next() // I am here 3 I'll have coffee in seconds
setTimeout(() => {
}, 3 * 1e3)

After the code runs , We'll get one first cooking Of log,
And then in 3s I'll get another one after that log.

This explains Generator What is it? :
An iterator that can pause
call next To get data ( We decide for ourselves whether or not to make coffee
In case of yield After that, the execution of the function will stop ( It's a full cup , The valve is closed
Let's decide when to run the rest of the code next When do you want to drink and then cook

This is a Generator The most important feature of , We only get the next value when we really need it , Instead of getting all the values at once

Generator The grammar of

Statement Generator There are many ways to function , The most important thing is , stay function After the keyword, add a *

function * generator () {}
function* generator () {}
function *generator () {} let generator = function * () {}
let generator = function* () {}
let generator = function *() {} // Examples of mistakes
let generator = *() => {}
let generator = ()* => {}
let generator = (*) => {}

perhaps , Because it's a function , It can also exist as an attribute of an object :

class MyClass {
* generator() {}
*generator2() {}
} const obj = {
*generator() {}
* generator() {}

generator Initialization and reuse of

One Generator Function by calling the method twice , Two completely independent State machine
therefore , Save the current Generator Objects matter :

function * generator (name = 'unknown') {
yield `Your name: ${name}`
} const gen1 = generator()
const gen2 = generator('Niko Bellic') gen1.next() // { value: Your name: unknown , done: false}
gen2.next() // { value: Your name: Niko Bellic, done: false}

Method: next()

Most commonly used next() Method , Whenever it is called , Will get the return object of the next output ( The call after code execution will always return {value: undefined, done: true}).

next Always returns an object , Contains two property values :
valueyield The value of the expression after the keyword
done : If there is no more yield Keyword. , Will return true .

function * generator () {
yield 5
return 6
} const gen = generator() console.log(gen.next()) // {value: 5, done: false}
console.log(gen.next()) // {value: 6, done: true}
console.log(gen.next()) // {value: undefined, done: true}
console.log(gen.next()) // {value: undefined, done: true} -- Subsequent calls will also be the result

Use as an iterator

Generator The function is an iterative , therefore , We can go straight through for of To use it .

function * generator () {
yield 1
yield 2
return 3
} for (let item of generator()) {
} //

return Not participating in iteration
Iterations perform all of the yield, in other words , After the iteration Generator Object will no longer return any valid values

Method: return()

We can call... Directly on the iterator object return(), To terminate subsequent code execution .
stay return After all next() Calls will return {value: undefined, done: true}

function * generator () {
yield 1
yield 2
yield 3
} const gen = generator() gen.return() // {value: undefined, done: true}
gen.return('hi') // {value: "hi", done: true}
gen.next() // {value: undefined, done: true}

Method: throw()

Calling throw() After that, it will also terminate all yield perform , An exception is thrown at the same time , Need to pass through try-catch To receive :

function * generator () {
yield 1
yield 2
yield 3
} const gen = generator() gen.throw('error text') // Error: error text
gen.next() // {value: undefined, done: true}

Yield The grammar of

yield Its grammar is a bit like return, however ,return It returns the result at the end of the function call
And calling return Nothing else will be done after that

function method (a) {
let b = 5
return a + b
// The following two sentences will never be executed
b = 6
return a * b
} method(6) //
method(6) //

and yield It's not the same

function * yieldMethod(a) {
let b = 5
yield a + b
// On the second execution `next` when , The next two lines will execute
b = 6
return a * b
} const gen = yieldMethod(6)
gen.next().value //
gen.next().value //


yield* Used to put a Generator Put it on the other Generator Execute in function .
It's kind of like [...] The function of :

function * gen1 () {
yield 2
yield 3
} function * gen2 () {
yield 1
yield * gen1()
yield 4
} let gen = gen2() gen.next().value //
gen.next().value //
gen.next().value //
gen.next().value //

yield The return value of

yield Can receive the return value , The return value can be used in subsequent code
A strange way of writing

function * generator (num) {
return yield yield num
} let gen = generator(1) console.log(gen.next()) // {value: 1, done: false}
console.log(gen.next(2)) // {value: 2, done: false}
console.log(gen.next(3)) // {value: 3, done: true }

We're calling for the first time next When , The code executes to yield num, Return at this time num
Then we call next(2), The code executes yield (yield num), And the value that we return is what we're doing next The parameters passed in the , As yield num The return value of exists .
And finally next(3), This part of the code is executed return (yield (yield num)), The second time yield Return value of expression .

Some actual use scenarios

All of the examples above are based on a known number of Generator Functional , But if you need an unknown number of Generator, Just create an infinite loop .

A simple random number generation

For example, we will achieve the acquisition of a random number :

function * randomGenerator (...randoms) {
let len = randoms.length
while (true) {
yield randoms[Math.floor(Math.random() * len)]
} const randomeGen = randomGenerator(1, 2, 3, 4) randomeGen.next().value // Returns a random number

Instead of some recursive operations

The most famous Fibonacci number , Basically, you choose to use recursive implementation
But combined with Generator in the future , You can use an infinite loop to achieve :

function * fibonacci(seed1, seed2) {
while (true) {
yield (() => {
seed2 = seed2 + seed1;
seed1 = seed2 - seed1;
return seed2;
} const fib = fibonacci(0, 1);
fib.next(); // {value: 1, done: false}
fib.next(); // {value: 2, done: false}
fib.next(); // {value: 3, done: false}
fib.next(); // {value: 5, done: false}
fib.next(); // {value: 8, done: false}

And async/await The combination of

Reiterated , I personally don't think async/await yes Generator The grammar sugar of ..

If it's children's shoes written on the front end , Basically, you will encounter the time when you load data by paging
If combined with Generator+asyncawait, We can do this :

async function * loadDataGenerator (url) {
let page = 1 while (true) {
page = (yield await ajax(url, {
data: page
})) || ++page
} // Use setTimeout Impersonate asynchronous request
function ajax (url, { data: page }) {
return new Promise((resolve) => {
setTimeout(_ => {
console.log(`get page: ${page}`);
}, 1000)
} let loadData = loadDataGenerator('get-data-url') await loadData.next()
await loadData.next() // force load page 1
await loadData.next(1)
await loadData.next() // get page: 1
// get page: 2
// get page: 1
// get page: 2

In this way, we can implement a paging control function in a few lines of code .
If you want to load a specific page number from , Direct will page Pass in next that will do .


Generator There are more ways to use it ,( Realize asynchronous process control 、 Read data on demand )
Personally think that ,Generator The advantage of is the lazy execution of the code ,Generator What is achieved , We can do it without it , Just use Generator after , Can make code more readable 、 The process becomes clearer 、 More focused on the implementation of logic .

If there's something you don't understand or Some mistakes in the article , Welcome to point out

Reference material

  1. Javascript (ES6) Generators — Part I: Understanding Generators
  2. What are JavaScript Generators and how to use them

Article example code

Generator More articles about the correct way to open

  1. C++11 The right way to open random numbers

    C++11 The right way to open random numbers stay C++11 Before , There is a problem in the existing random number functions : When using the loop to get random number many times , If the program runs too fast or uses multithreading and other methods ,srand((unsigned)time(null ...

  2. iOS Develop tips -- The right way to open a camera album

    iOS The right way to open a camera album - UIImagePickerController By designation sourceType To open an album or a camera UIImagePickerControllerSourceTypeP ...

  3. Xcode The right way to open ——Debugging( Reprint )

    Xcode The right way to open ——Debugging   Programmers spend a lot of time in their daily development debug On , be engaged in iOS Development inevitably requires the use of Xcode. This blog mainly introduces Xcode Several kinds of energy ...

  4. C# grammar —— Many applications of generics C# grammar ——await And async The right way to open C# Thread safe use ( 5、 ... and ) C# grammar —— A tuple type Work hard redis and memcached The difference between

    C# grammar —— Many applications of generics   This article mainly introduces the application of generics . Generics are .NET Framework 2.0 Version of the class library already provides Syntax , It is mainly used to improve the reusability of code . Type security and efficiency . Definition of generics The following defines ...

  5. InnoDB Buffer pool preload in MySQL 5.7 The right way to open in

    InnoDB Buffer pool preload in MySQL 5.7 The right way to open in https://mp.weixin.qq.com/s/HGa_90XvC22anabiBF8AbQ In this article , I'm going to talk about MySQL 5 ...

  6. Console The right way to open the console

    Console The right way to open the console console Object provides access to browser debug mode information to the console -- Console object |-- assert() If the first parameter asserts to be false, The error message is output on the console ...

  7. The correct way to open task queues and asynchronous interfaces (.NET Core edition )

    The correct way to open task queues and asynchronous interfaces What is an asynchronous interface ? Asynchronous Operations Certain types of operations might require processi ...

  8. ( One )Redis for Windows Proper opening

    Catalog ( One )Redis for Windows Proper opening ( Two )Redis for Alicloud public network connection ( 3、 ... and )Redis for StackExchange.Redis Download address Official website . Chinese net 1 And in ...

  9. List Of remove() Three correct ways to open a method

    turn : java Programming :List Of remove() Three correct ways to open a method ! 2018 year 08 month 12 Japan 16:26:13 Aries9986 Read the number 2728 more Category column : leetcode Brush problem   Copyright voice ...

Random recommendation

  1. Solr Introduction (6) The configuration file solrconfig.xml

    solrconfig.xml Contains most of the parameters used to configure your own behavior , Its scope of action is the current core. The file is located at ${solr_home}/solr/core1/conf/ Next . Parameter list Overview : A.lib B.d ...

  2. OBD Chip application development manual OBD2 Development Internal data sharing Development of automotive electronic communication TDA61 TDA66 chip

    OBD Products and various automotive electronics related development . Developers are often required to learn about various car protocols , Learn more about all OBD Specifications and vehicle performance parameters . It often takes a long time for developers to learn and Research , A great delay OBD Product launch development progress . For this reason, Shenzhen core solution electronic company ...

  3. Incremental upgrade ( Provincial Traffic update ) Of Android Client implementation

    Reprint and zhouhuiah The column  http://blog.csdn.net/zhouhuiah/article/details/16939937 This article adds exception handling on the basis of the above two blogs , And will generate ...

  4. Android Development -API guide - Device compatibility

    Device Compatibility The original English text :http://developer.android.com/guide/practices/compatibility.html Date of collection :2014- ...

  5. Realization div Scrolling of pictures in

    I have nothing to do today. I wrote a picture to scroll : Source code : <html><head> <meta charset="utf-8"/> <script typ ...

  6. Java--JDBC Connect to database

          We know Java Medium jdbc It's used to connect applications and data systems , This article is mainly about JDBC Implementation and use details of . It mainly includes the following contents : JDBC Basic knowledge of ( Data drivers ) JDBC Connection configuration ...

  7. fzu 2257 saya My bear biscuit

    https://vjudge.net/problem/FZU-2257 The question : A little Ideas : Look at the problem solving and filling . It is difficult to find the probability . First , Because the dimensions are independent . So x For example . First , The calculation can take (i,j) ...

  8. 6 nucleus CPU Lead to SQL2005 When installing “ Unable to start service ” wrong

    New on Monday IBM3650M3 On the server of SQL server2005 Halfway through the installation , newspaper " Tips :SQL Server Service failed to start ." wrong . Changed several operating system versions and changed several versions of sq ...

  9. Python Data structure and algorithm related problems and solutions

      1. How to list , Dictionaries , Filter the data in the set according to the criteria ¶ In [1]: from random import randint In [2]: data = [randint(-10,10) for _ ...

  10. linux Change password command

    1.passwd command   The syntax in the script :echo "password" | passwd testuser --stdin > /dev/null 2>&1 or (e ...