In this lessons, we are going to explore one really great new ishhhh that was introduced into the javascript ecosystem and native to javascript now, moreover we most times say that its a function that resembles async/await
Fun Fact β Async Await is actually built on generators π
Now donβt get me wrong its not exactly ASYN / AWAIT its got almost a different flare to it, but its very similar in the sense that in async / await functions we AWAIT our Asynchronous events (our promised based events) where we pause the execution inside of our Asynchronous whenever we see the await call.
Well, our generator functions are very similar in the sense that they also pause their executions whenever they see a specific key inside of their function and that key is called a yield. now in other, for us to use this or achieve this there is a special syntax we actually have to declare our old school way of defining our function decorator but this time with a star beside it like this.
//codes here
function* gen(){
// code goes here
}
Now let's get to understand these things better, let's declare two console.logβs and see something here
//codes here
function* gen(){
console.log('Hello There');
console.log('I am a generator');
}
// Now i'd declear my gen function to a const
const gfunc = gen()
// this would return undefined
//when i call gfunc in the console i get these weird suspended and they are called a generator object
/* gen {<suspended>} __proto__:
Generator [[GeneratorLocation]]:
VM275:1 [[GeneratorStatus]]:
"suspended" [[GeneratorFunction]]: Ζ* gen()
[[GeneratorReceiver]]: Window [[Scopes]]: Scopes[3]
**/
Now I know you might be a lot surprised at what's happening and why it's not doing our regular function executions where we would see our logs and all, but here is what we do on it, we call a .next()
on it, and what .next()
does is that I would resume the execution inside of our function, so at the point where we invoked it for the first time we instantiated this generator object that actually is aware of the code inside of our function but the execution inside of the gen()
function is paused.
I know this might be a lot but it's easy what we do, in other to resume this function we just call the .next()
on the gfunc
const so until we call .next()
on our function might not be able to run the execution
gfunc.next()
//Now this returns some things I want you to take note of
Hello There I am a generator
{ value: undefined, done: true }
Now we get our log and an additional object and this object contains our value prop and a done property, now the done property tells us if there is any code to still run and in our case, there is none so we get true. now lets clear this up and go into something a bit advance
function* gen(i){
yield i;
yield i + 5;
}
cosnt gfunc = gen(10)
so now what we have done is that we have a gen()
function that takes in I as an argument and then we yield the argument we parse in, and the argument plus 5 then we declared a const and gave it a value of 5. are we good? YES! so when we call a gfunc.next()
let's see what we get.
gfunc.next()
//returns
{
value: 5,
done: false
}
so now we see that the value property in the object is the initial yield we mapped in the function and the done is false, why? now that's because we are not done playing our execution in the function meaning that there is more in the function it only paused after our first yield, now let's see what happens when we do .next()
again
gfunc.next()
//returns
{
value: 10,
done: false
}
now we see that the value property in the object now contains our updated value and our done property is still false, now this is because in our yield function we never declared a return value and this is required so our generator function can know when to stop the execution. so now if we add a return value we see that our done returns true like this
function* gen(i){
yield i;
yield i + 5;
return 20;
}
cosnt gfunc = gen(10)
// first execution
gfunc.next()
//returns
{
value: 5,
done: false
}
//second execution
gfunc.next()
//returns
{
value: 10,
done: false
}
//final execution
gfunc.next()
//returns
{
value: 20,
done: true
}
Now you see that we have our done value as true after the execution is done. this is primarily the base use of generator functions if you want to stash multiple executions but you want to control when you want to pause and play the execution. think of it as
An ability to pause functions
I think we should stop here for now. so the key thing you need to remember is, wherever we see yield that means our code is paused at that point even if its an Asynchronous code just like async / await.
I know that we have spent a lot of time talking about generator functions but then if you don't still understand, you can go over the article over and over again or Iβd but in some great resources to aid your learning. see you in my other articles π
Top comments (1)
To this day I still haven't found a single use for generators. Much as I'd love to use them.