Generator in JavaScript

generator function js

In ECMA2015 generators are introduced in javascript. Functions in Javascript run until return or end. Generators run until yield or return or end. Generator is a process that can be passed and resumed and can yield multiple values. It provides a new way of working with functions and iterators.

Using a generator:

  • You can stop the execution of a function from anywhere inside the function.
  • Continue executing from pause position.

Regular function return only one single value or nothing. It is executed upto completion. It cannot pause in middle and continue from pause position.

On the other hand generators can yield multiple values, one after another on demand. It works with iterators, to create a data stream with ease.

Create Generators:

To create a generator, we define a generator function with *. The objects of generator function are called generators.

Syntax:
// define a generator function
function* generator_function() {
   ... .. ...
}

// creating a generator
const generator_object = generator_function();

This generator function can also be defined in expressions

// Generator function expression
const generatorFunction = function*() {}
Using yield and next():

Generator function once called returns generator object, which holds generator iterable that can be iterated using next() method or for … of loop.

Every next() method executes every line of code until next yield it encounter and suspends its execution temporarily.

// generator function
function* generatorFunc() {

    console.log("1 invoke");
    yield 1;
    
   console.log("2 invoke");
    yield 2;
}

// returns generator object
const generator = generatorFunc();
console.log(generator.next());
Output:

1 invoke

{ value: 1, done: false }

Here a generator object is created. When generator.next() is called it executes upto yield 1 and pause the execution.

Using multiple yields:
// generator function
function* generatorFunc() {

    console.log("1 invoke");
    yield 1;
    
   console.log("2 invoke");
    yield 2;
   console.log("3 invoke");
}

// returns generator object
const generator = generatorFunc();

console.log(generator.next());
console.log(generator.next());
console.log(generator.next());
Output:

1 invoke

{ value: 1, done: false }

2 invoke

{ value: 2, done: false }

3 invoke

{ value: undefined, done: true }

Here after first generator.next() executes 1 invoke upto yield 1 and pause.

Second generator.next() executes from pause position and executes 2 invoke upto yield 2 and pause again.

Third generator.next() executes from pause position and all yields are accessed so returns { value: undefined, done: true }

Using for… of loop:

Since generators are iterables we use for … of loop.

// generator function

function* generatorFunc() {

    console.log("1 invoke");

    yield 1;
console.log("2 invoke");

    yield 2;

}

// returns generator object

const generator = generatorFunc();

for ( const g of generator){

   console.log(g);

}
Output:

1 invoke

1

2 invoke

2

Generator methods:
MethodDescription
next()Returns a value of yield
return()Returns a value and terminates the generator
throw()Throws an error and terminates the generator
Generator states:

The next table lists the possible states of a Generator object:

StatusDescription
suspendedGenerator has halted execution but has not terminated.
closedGenerator has terminated by either encountering an error, returning, or iterating through all values.
Return vs yield keyword:
return keywordyield keyword
returns the value and terminates the functionreturns the value and pause the function
available in both normal and generator functionavailable only in generator function
Using return :
// generator function
function* generatorFunc() {

    yield 1;

   return 22;

    yield 3;
}
// returns generator object
const generator = generatorFunc();

console.log(generator.next());
console.log(generator.next());
console.log(generator.next());
Output:

{ value: 1, done: false }

{ value: 22, done: true }

{ value: undefined, done: true }

We can use return() method instead of return keyword as generator.return()

Here when return statement is encountered it returns the value, done is set to true and terminates the function and return nothing after that.

Generator throw() method:
// generator function
function* generatorFunc() {
    yield 100;
    yield 200;
}

// returns generator object
const generator = generatorFunc();
console.log(generator.next());

// throws an error
// terminates the generator
console.log(generator.throw(new Error('Error occurred.')));
console.log(generator.next());
Output:

{ value: 100, done: false }

Error: Error occurred.

How to use Generators in Python?

In Python, creating a iterator is a bit tricky, we need to implement _iter_( ) and _next_( ) method to keep track of internal states and raise StopIteration when there is no value to be returned. So in such cases, Generators are used.

What is Python Generators?

Python generator is a special type of function that returns a traversal object which is used to create iterators. In a generator function yield keyword is used rather than return.

Difference between yield and return statement

If a function contains at least one yield statement it becomes a generator function. Both yield and return will return some value from a function. But return statement terminates the function entirely whereas yield statement pauses the function temporarily holding all the internal states of the function and continues in further successive calls.

Difference between Generator function and normal function:

  • Generator function has one or more yield keywords.
  • When called, it returns a traversal object (iterator) but does not start immediately
  • Once the function yields, the function is paused and control is transferred to the caller.
  • Local variables and their states are remembered between successive calls
  • Methods like _iter_() and _next_() are implemented automatically. We can iterate using next().
  • When function terminates, StopIteration is raised automatically.
Example:

As you can see in the above example, when the function terminates, StopIteration is raised automatically.

Python Generator with a Loop:

Normally generator functions are implemented in a loop with a terminating condition.

Generator Expression:

            Simple Generators can be created on the go using Generator expressions. It’s similar to lambda expression, which creates anonymous function. Generator expression also creates anonymous function.

            Syntax is like list comprehension in Python. But instead of a square bracket round parentheses is used. The list comprehension calculates entire list whereas generator expression calculates one at a time.

Advantages:

  • Easy to implement
  • Memory efficient
  • Represent infinite sequence
  • Pipelining with generators.