Generator

Regular functions return a single value (or no value at all).

The Generator can return (” yield “) multiple values one after the other on demand. They work perfectly with Iterable, making it easy to create data streams.

The Generator function

To create a generator, we need a special syntactic construct: function*, known as “generator function”.

It looks something like this:

function* generateSequence() {
  yield 1;
  yield 2;
  return 3;
}
Copy the code

Generator functions behave differently from regular functions. When such a function is called, it does not run its code. Instead, a special object called a “Generator Object” is returned to manage the execution process.

Let’s look at an example:

function* generateSequence() {
  yield 1;
  yield 2;
  return 3;
}

// "generator function" creates a generator object
let generator = generateSequence();
alert(generator); // [object Generator] 
Copy the code

So far, the function body code in the above code has not been executed:

The main method of a generator is next(). When called, it resumes the run shown above, executing up to the latest yield

statement (value can be omitted; default is undefined). The function is then paused and the value of the output is returned to the external code. The result of next() is always an object with two attributes:

  • valueA: Specifies the value of the output.
  • done: if the generator has completed executiontrue, or forfalse.

For example, we can create a generator and get the (expressde) value for its first output:

function* generateSequence() {
  yield 1;
  yield 2;
  return 3;
}

let generator = generateSequence();

let one = generator.next();

alert(JSON.stringify(one)); // {value: 1, done: false}
Copy the code

So far, we’ve only got the first value, and now the function is on the second line:

Let’s call it againgenerator.next(). The code resumes execution and returns to the nextyieldValue:

let two = generator.next();

alert(JSON.stringify(two)); // {value: 2, done: false}
Copy the code

If we call it a third timegenerator.next(), the code will execute toreturnStatement, which completes the execution of the function:

let three = generator.next();

alert(JSON.stringify(three)); // {value: 3, done: true}
Copy the code

Generator execution is now complete. We’re throughdone:trueYou can see that, and willvalue:3Process as final result.

It no longer makes sense to make a new call to generator.next(). If we do this, it will return the same object: {done: true}.

The function * f (…). Or the function * f (…). ?

Both grammars are correct.

However, the first syntax is generally preferred because the asterisk * indicates that it is a generator function, which describes the type of function rather than the name of the function, and therefore * should be attached to the function keyword.


The Generator is iterable

When you look at the next() method, you might have guessed that the generator is iterable. (Next () is a necessary method for iterator.)

We can use for.. The of loop iterates through all of its values:

function* generateSequence() {
  yield 1;
  yield 2;
  return 3;
}

let generator = generateSequence();

for(let value of generator) {
  alert(value); // 1, then 2
}
Copy the code

for.. Does “of” look more elegant than.next().value?

… Note, however, that the above example displays a 1, then a 2, and then no more. It won’t show 3!

This is because when done: true, for.. The of loop ignores the last value. So if we want to pass for.. The of loop displays all the results, and we must yield them:

function* generateSequence() {
  yield 1;
  yield 2;
yield 3;
}

let generator = generateSequence();

for(let value of generator) {
  alert(value); // 1, then 2, then 3
}
Copy the code

Because the generator is iterable, we can use all the relevant features of Iterator, for example: spread syntax… :

function* generateSequence() {
  yield 1;
  yield 2;
  yield 3;
}

let sequence = [0. generateSequence()]; alert(sequence);// 0, 1, 2, 3
Copy the code

In the code above… GenerateSequence () converts an iterable generator object to an array


Use generator for iteration

In Iterable Object, we can create an Iterable range object that returns from.. The value of the to.

let range = {
  from: 1.to: 5.// for.. Of Range calls this method once at the beginning
  [Symbol.iterator]() {
    / /... It returns the iterator object:
    // For.. Of will target this object only and request the next value from it using next()
    return {
      current: this.from,
      last: this.to,

      // for.. The of loop calls next() on each iteration
      next() {
        // It should take the object {done:.. , value :... } returns a value of the form
        if (this.current <= this.last) {
          return { done: false.value: this.current++ };
        } else {
          return { done: true}; }}}; }};// Iterate through the range object, returning all numbers in the range from 'range.from' to 'range.to'
alert([...range]); / / 1, 2, 3, 4, 5
Copy the code

Iterator we can use generator to iterate by providing a generator function as symbol. iterator:

Here is an identical range, but much more compact:

let range = {
  from: 1.to: 5, * [Symbol.iterator]() { // [Symbol. Iterator]: function*()
    for(let value = this.from; value <= this.to; value++) {
      yieldvalue; }}}; alert( [...range] );/ / 1, 2, 3, 4, 5
Copy the code

The code works because range[symbol.iterator]() now returns a generator, and the generator method is for.. Expected of:

  • It has a.next()methods
  • It takes{value: ... , done: true/false}Returns a value in the form of

Of course, this is no coincidence. Generator was added to the JavaScript language with iterator in mind to make it easier to implement iterator.

The variant with generator is much cleaner than the original Range iteration and retains the same functionality.

The Generator can yield values forever

In the example above, we generated a finite sequence, but we could also create a generator that generates an infinite sequence, yielding values all the time. For example, an unordered sequence of pseudo-random numbers.

In this case there is definitely a need in generator for.. Add a break (or return) to the of loop. Otherwise the loop repeats forever and hangs.


Reprint details:

Reprint site: javascript.info

Address: reprinted useful. Javascript. The info/generators