JavaScript | Generator

Like Python Generators, JavaScript also supports Generator functions and Generator Objects.

Generator-Function : A generator-function is defined like a normal function, but whenever it needs to generate a value, it does so with the yield keyword rather than return. The yield statement suspends function’s execution and sends a value back to caller, but retains enough state to enable function to resume where it is left off. When resumed, the function continues execution immediately after the last yield run.

Syntax :

// An example of generator function
function* gen(){
     yield 1;
     yield 2;
     ...
     ...
}

Generator-Object : Generator functions return a generator object. Generator objects are used either by calling the next method on the generator object or using the generator object in a “for of” loop (as shown in the above program)
The Generator object is returned by a generating function and it conforms to both the iterable protocol and the iterator protocol.

filter_none

edit
close

play_arrow

link
brightness_4
code

<script>
// Generate Function generates three 
// different numbers in three calls
function * fun()
{
    yield 10;
    yield 20;
    yield 30;    
}
  
// Calling the Generate Function
var gen = fun();
document.write(gen.next().value);
document.write("<br>");
document.write(gen.next().value);
document.write("<br>");
document.write(gen.next().value);
</script>                    

chevron_right


Below is an example code to print infinite series of natural numbers using a simple generator.



filter_none

edit
close

play_arrow

link
brightness_4
code

<script>// Generate Function generates an 
// infinite series of Natural Numbers 
function * nextNatural()
{
    var naturalNumber = 1;
  
    // Infinite Generation
    while (true) {
        yield naturalNumber++;
    }
}
  
// Calling the Generate Function
var gen = nextNatural();
  
// Loop to print the first
// 10 Generated number
for (var i = 0; i < 10; i++) {
  
    // Generating Next Number
    document.write(gen.next().value);
  
    // New Line
    document.write("<br>");
}
</script>

chevron_right


Output

1
2
3
4
5
6
7
8
9
10

Below is an example of how to manually return from a generator

filter_none

edit
close

play_arrow

link
brightness_4
code

<script>
  
var array = ['a', 'b', 'c'];
function* generator(arr) {
  let i = 0;
  while (i < arr.length) {
    yield arr[i++]
  }
}
  
const it = generator(array);
  
// we can do it.return() to finish the generator
  
</script>

chevron_right


Encountering yield and yield* syntax

yield : pauses the generator execution and and it returns the value of the expression which is being written after the yield keyword.

yield* : it iterates over the operand and returns each value until done is true.

filter_none

edit
close

play_arrow

link
brightness_4
code

<script>
  
const arr = ['a', 'b', 'c'];
  
function* generator() {
  yield 1;
  yield* arr;
  yield 2;
}
  
for (let value of generator()) {
  document.write(value);
  document.write("<br>");
}
  
</script>

chevron_right


Output

1
a
b
c
2

Another method to create iterable

filter_none

edit
close

play_arrow

link
brightness_4
code

<script>
  
var createOwnIterable = {
  *[Symbol.iterator]() {
    yield 'a';
    yield 'b';
    yield 'c';
  }
}
  
for (let value of createOwnIterable) {
  document.write(value);
  document.write("<br>");
}
  
<script>

chevron_right


Output



a
b
c

Return from generator function

filter_none

edit
close

play_arrow

link
brightness_4
code

<script>
  
function* generator() {
  yield 'a';
  return 'result';
  yield 'b';
}
  
var it = generator();
document.write(JSON.stringify(it.next()));
// {value: "a", done: false}
document.write(JSON.stringify(it.next()));
// {value: "result", done: true}
  
</script>

chevron_right


How to throw an exception from generator

filter_none

edit
close

play_arrow

link
brightness_4
code

<script>
  
function* generator() {
  throw new Error('Error Occured');
}
  
const it = generator();
it.next();
// Uncaught Error: Error Occurred
  
</script>

chevron_right


Calling a generator from another generator

filter_none

edit
close

play_arrow

link
brightness_4
code

<script>
  
function* firstGenerator() {
  yield 2;
  yield 3;
}
  
function* secondGenerator() {
  yield 1;
  yield* firstGenerator();
  yield 4;
}
  
  
for (let value of secondGenerator()) {
  document.write(value)
  document.write("<br>");
}
  
</script>

chevron_right


Output

1
2
3
4

Limitation of Generators
you can’t yield inside a callback in generators

filter_none

edit
close

play_arrow

link
brightness_4
code

<script>
  
function* generator() {
  ['a', 'b', 'c'].forEach(value => yield value) // This will give syntax error
}
  
</script>

chevron_right


Using async generators (for api call)

filter_none

edit
close

play_arrow

link
brightness_4
code

<script>
  
const firstPromise = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve(1), 5000)
  })
}
  
const secondPromise = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve(2), 3000)
  })
}
  
async function* generator() {
  const firstPromiseResult = await firstPromise();
  yield firstPromiseResult;
  const secondPromiseResult = await secondPromise();
  yield secondPromiseResult;
}
  
var it = generator();
for await(let value of it){
  document.write(value);
  document.write("<br>");
}
  
</script>

chevron_right


Output

(after 5 seconds)
1 
(after 3 seconds)
2

Advantages of generators:
They are memory efficient as lazy evaluation takes place, i.e, delays the evaluation of an expression until its value is needed.

use-case (generators)

  • writing generators in redux-saga
  • async-await (Implemented with promise and generators)

full-stack-img




My Personal Notes arrow_drop_up

Check out this Author's contributed articles.

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.