Generators in JavaScript are a valuable tool for creating functions that can be paused and resumed, allowing other code to execute in the meantime. By incorporating the keyword “yield,” generators can halt their execution and give control to other code until they are ready to resume. This powerful feature opens up new programming possibilities and can significantly improve code efficiency.

To define a generator function, we use the * symbol before the function keyword. It’s important to note that this * notation should not be confused with the pointer dereference operator used in lower-level languages like C or Go. Generators can have multiple yield keywords, allowing them to pause execution at different points.

Some advantages of using generators in JavaScript include:

  1. Two-way communication during execution: Generators can communicate with the calling code by yielding values. The calling code can pass values to the generator during the next() method call, allowing for dynamic behavior.

  2. Long-lived loops without freezing: Generators can be used to create infinite loops without freezing the program. Since generators can pause and resume their execution, they prevent the blocking of other code while the loop is running.

Let’s take a look at an example to understand how generators work:

function* calculator(input) {
  var doubleThat = 2 * (yield (input / 2));
  var another = yield (doubleThat);
  return (input * doubleThat * another);
}

To initialize the generator, we can create an instance:

const calc = calculator(10);

Next, we start the iterator on our generator using the next() method:

calc.next();

In the first iteration, the generator function runs until it encounters the yield keyword. The code then returns an object with the value property set to 5 and the done property set to false. This indicates that the iteration is not yet complete.

For the second iteration, we pass the value 7 to the generator:

calc.next(7);

Now, 7 is assigned to the variable doubleThat. It’s important to note that the value input / 2 is not an argument but rather the return value of the previous iteration. The code then multiplies doubleThat by 2 and reaches the second yield keyword, returning 14.

In the final iteration, we pass 100 to the generator:

calc.next(100);

The returned object now has its done property set to true, indicating that there are no more yield keywords. The value property is set to 14000, which is the result of the expression (input * doubleThat * another), or 10 * 14 * 100.

Using generators in JavaScript can greatly improve code organization and execution flow. Their ability to pause and resume execution allows for complex operations to be handled more efficiently, leading to more robust and streamlined applications.