Skip to content

32 Generators

Biswajit Sundara edited this page Aug 18, 2023 · 1 revision

Generator is simply a function that can be paused.

  • In other words a function that returns an object on which we can call next().
  • Every invocation of next() will return an object of shape { value: Any, done: true|false}

Syntax

function* name(){
   const variable = yield value;
}

1. Basic Example

  • We will notice, its returning object each time next() is called.
  • And the Object is having two properties: value & true | false.
  • The last line prints true, because that time the function has completed generating values and there is nothing more to return.
const getNumbers = function* (){
    yield 1;
    yield "hello";
    yield "true";
    yield {name:"Biswajit"};
    return "i am done";
}

const numberGen = getNumbers();
console.log(numberGen.next());
console.log(numberGen.next());
console.log(numberGen.next());
console.log(numberGen.next());
console.log(numberGen.next());

------------- OUT PUT ---------------
{ value: 1, done: false }
{ value: 'hello', done: false }
{ value: 'true', done: false }
{ value: { name: 'Biswajit' }, done: false }
{ value: undefined, done: true }

2. Accessing the values

We can directly access the values this way.

console.log(numberGen.next().value);
console.log(numberGen.next().value);
console.log(numberGen.next().value);
console.log(JSON.stringify(numberGen.next().value));
console.log(numberGen.next().value);

3. Running through loops

const getNumbers = function* (numbers){
    for(let i=0;i<numbers.length;i++){
         yield numbers[i];
    }
}

const getNumbersGen = getNumbers([1,2,3,4,5]);

const interval = setInterval(()=>{
   const next = getNumbersGen.next();
   if(next.done){
       console.log("This generator is done");
       clearInterval(interval);
   }
   else{
       const number = next.value;
       console.log(number);
   }
},1000);

---------------- OUTPUT -------------------
1
2
3
4
5
This generator is done

4. Generator & Promises

This will make codes more cleaner and easy to debug.

A. Without Generator
Problems with this approach is look at the layers. If we have to catch errors then we will have to write catch block for all the promises which will make it more ugly.

const getRandomUsers = ((numberOfUsers)=>{
    const fetchUsers = fetch(`https://randomuser.me/api/?results=${numberOfUsers}`);
    console.log(fetchUsers);
    fetchUsers.then((response)=>{
        response.json().then((randomusers)=>{
             console.log(JSON.stringify(randomusers));
             console.log(JSON.stringify(randomusers.results.length));

             randomusers.results.array.forEach(user => {
                 const {gender, email} = user;
                 console.log(`${gender} ${email}`);
             });
        })
    })
})

getRandomUsers(5);

B. Coroutine
For this we will have to install 'bluebird' library. Here we are using promises and generators together and it makes the code much cleaner and to debug easily.

import { coroutine as co } from 'bluebird';

const getRandomUsers = co(function* (numberOfUsers) {
    const fetchUsers = yield fetch(`https://randomuser.me/api/?results=${numberOfUsers}`);
    const response = yield fetchUsers.json();
    return response;
});

getRandomUsers(10).then((randomusers) => {
    randomusers.results.array.forEach(user => {
        const { gender, email } = user;
        console.log(`${gender} ${email}`);
    });
}).catch((err)=>{
    console.log(err);
})

Clone this wiki locally