“This is the 11th day of my participation in the First Challenge 2022. For details: First Challenge 2022.”

What is a generator

Generators are a new function control scheme in ES6 that gives you the flexibility to control when a function executes and when it pauses. A generator function is also a function, which differs from a normal function:

(1) Generator functions need * after function

(2) Generator functions use the yield keyword to control the execution and pause of functions

The Generator function returns a Generator.

A generator is essentially a special iterator.

Generator function

Foo is a generator function because it meets the criteria for generator functions: (1) function followed by *, (2) use yield to control the execution and pause of the function, and (3) when foo is called, it returns a generator object that is a special iterator. We can call the next method.

function* foo() {
  console.log('Function starts executing');

  const value1 = 100
  console.log('First code:', value1);
  yield

  const value2 = 200
  console.log('Second code:', value2);
  yield

  const value3 = 300
  console.log('Third code:', value3);
  yield

  console.log('End of function execution');
}
Copy the code
When a generator function is called, we are returned with a generator object
const generator = foo()

// Start executing the first code
generator.next()

// Start executing the second code
generator.next()
generator.next()
generator.next()
generator.next()
generator.next()
generator.next()
Copy the code

The execution flow of generator functions

The execution of the function is paused when yeild is encountered and terminated when return is encountered.

function* foo() {
  console.log('Function starts executing');

  const value1 = 100
  console.log('First code:', value1);
  yield value1

  const value2 = 200
  console.log('Second code:', value2);
  yield value2

  const value3 = 300
  console.log('Third code :', value3);
  yield value3

  console.log('End of function execution');
  return '123'
}

const generator = foo()
console.log('Return value 1:', generator.next());
console.log('Return value 2:', generator.next());
console.log('Return value 3:', generator.next());
console.log('Return value 4:', generator.next());
Copy the code

Generator passing parameters

With yield we allow the function to pause the piecewise execution. Functions can pass arguments, so how do we pass arguments to segmented functions?

When we call next, we can pass it an argument that will be the return value of the previous yield statement.

function* foo() {
  console.log('Function starts executing');
  const value1 = 100
  console.log('First code:', value1);
  const n = yield value1

  const value2 = 200 * n 
  console.log('Second code:', value2);
  const count = yield value2

  const value3 = 300 * count
  console.log('Third code:', value3);
  yield value3

  console.log('End of function execution');
  return '123'
}

const generator = foo()
console.log(generator.next());
console.log(generator.next(10)); // The second next argument is the return value of the first yield
console.log(generator.next(20));

Copy the code

What if we want to pass parameters to the first paragraph? We can pass arguments when a function is called.

function* foo(num) {
  console.log('Function starts executing');
  const value1 = 100 * num
  console.log('First code:', value1);
  const n = yield value1

  const value2 = 200 * n 
  console.log('Second code:', value2);
  const count = yield value2

  const value3 = 300 * count
  console.log('Third code:', value3);
  yield value3

  console.log('End of function execution');
  return '123'
}

const generator = foo(5)
console.log(generator.next());
console.log(generator.next(10));
console.log(generator.next(20));
Copy the code

Generator terminates prematurely — return function

We can use return to terminate the generator prematurely, and then continue calling next without generating any more values.

function* foo(num) {
  console.log('Function starts executing');

  const value1 = 100 * num
  console.log('First code:', value1);
  const n = yield value1

  const value2 = 200 * n
  console.log('Second code:', value2);
  const count = yield value2

  const value3 = 300 * count
  console.log('Third code:', value3);
  yield value3

  console.log('End of function execution');
  return 123
}

const generator = foo(10)
console.log(generator.next());
console.log(generator.return(20));
Copy the code

The generator throws an exception — the throw function

We can catch exceptions inside the generator.

function* foo() {
  console.log('Code starts executing');

  const value1 = 100
  try {
    yield value1
  } catch (error) {
    console.log('Exception caught:', error);
    yield 123
  }
  console.log('Second code continues execution');
  const value2 = 200
  yield value2
  console.log('End of code execution');
}

const generator = foo()
console.log(generator.next());
console.log(generator.throw('error message')); 
console.log(generator.next());
Copy the code