DEV Community

Cover image for What the... generators!
Fabio Russo
Fabio Russo

Posted on

What the... generators!

Want to know about generators?

FIRST you need to check iterators

That's not something you can skip, because, generators work through iterators. We can say that generators are a simpler way to write our own iterators.

This is a generator:


function* breeds(){
    yield "labrador";
    return "chow-chow";
}

const iterator = breeds();

console.log(iterator.next())
//->{value: "labrador", done: false}
console.log(iterator.next())
//->{value: "chow-chow", done: true}
console.log(iterator.next())
//->{value: undefined, done: true}

Enter fullscreen mode Exit fullscreen mode

Let's see what's happening here.

First, we need to create a generator function, and we can do that by using a * between function and the function name.
No matter if it's:
function* breeds()
function *breeds()
const breeds = function *()
const breeds = function*()
This will work anyway!.

(But, It's a standard to use the * just after the function ... so try to always use the syntax function*.)

Inside that function we're using that yield ... what's that?
yield It's something listening to the next() calls.

Everytime we use the .next() on the iterator, the generator will use the next not yet used yield.
That's the same idea behind iterators and we're checking that, with the done key the iterators returns!.

If It's value is false the .next() will call the yield AFTER the previous one.


console.log(iterator.next())
//->{value: "labrador", done: false}
console.log(iterator.next())
//->{value: "chow-chow", done: true}
console.log(iterator.next())
//->{value: undefined, done: true}

Enter fullscreen mode Exit fullscreen mode

When the done:true will happens?
When there's no more to yield out that generator.

But we need to be more precise about this.

focus

We all know that a function, in JS, always returns something.
If you do not define a return, JS will do It for you, by returning an "undefined" at the end of It.


function* breeds(){
    yield "labrador";
    yield "chow-chow";
}

const iterator = breeds();

console.log(iterator.next())
//->{value: "labrador", done: false}
console.log(iterator.next())
//->{value: "chow-chow", done: false}
console.log(iterator.next())
//->{value: undefined, done: true}

Enter fullscreen mode Exit fullscreen mode

By taking away the return from the function, calling .next() will force JS to return a {value: undefined, done: true}

So JS still returns It for you, also with generators, because, we're still talking about functions here!

If you want to force a return you can use the .return() method on the iterator and finish the generator.


function* breeds(){
    yield "labrador";
    yield "chow-chow";
}

const iterator = breeds();

console.log(iterator.return("we <3 dogs"))
//->{value: "we <3 dogs", done: true}
console.log(iterator.next())
//->{value: undefined, done: true}
console.log(iterator.next())
//->{value: undefined, done: true}

Enter fullscreen mode Exit fullscreen mode

As you can see, we're immediately returning and finishing the generator with the .return() method!.

generators are not magic!

We're really not executing stuff by calling the generators ... indeed, we're using the iterator interface every time we're calling generators with the .next() method.

We can see the .next() as a remote controller to START (calling yield) and PAUSE (checking the done: value) the generator function

That's why, we need to define:


const iterator = breeds();


Enter fullscreen mode Exit fullscreen mode

and call the iterator.next()

(iterator It's just the variable name, not the iterator object itself)

lot of stuff can be done

In real life work, we can do really lot of stuff with generators.

We can use generators values with variables.
We can fetch, spread and use the for...of loop.

At the moment we're using generators to call one single yield at time, we can say, that we're using It in synchronous way.

But, generators can be also used in asynchronous way.
I'm not going to cover It now... you can check about Promises or async/await, and maybe, we we'll talk about that, another day.
Promises
Async

HAVE FUN WITH CODE
Pearl Jam

Top comments (3)

Collapse
 
dubyabrian profile image
W. Brian Gourlie

Very cool. I didn't realize that returning a value would mark the generator as done!

Collapse
 
kiho profile image
Kiho Chang

I really like to use generator in my project but debugging is real problem here.
I can't go beyond redux-saga which I have to use in my company project this time, any suggestion?

Collapse
 
genta profile image
Fabio Russo

You can use the .throw() method by calling the generator.

Make It an instanceof Error.
If thereโ€™s s an error the generator will stop the execution, by propagating the call to the next .throw() method.