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}
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}
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.
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}
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}
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();
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
Top comments (3)
Very cool. I didn't realize that
return
ing a value would mark the generator as done!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?
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.