Generators In Depth
The JavaScript Generators function can paused and resumed, The generators function are implementing using the asterisk(*) sign we have to add the asterisk sign after to the function keyword like this function*.
Generators are incomplete without the yield keyword, we have to use the yield keyword to paused the execution of the function, yield keyword also useful to get the value from the outside of the function or also you can say that yield keyword can help us to get the value from outside of the function using the next() method while pausing the execution of the function.
Yield can be return the value from the function and also receive the value from outside of the function.
Generators are helpful to us implementing following things in our program.
- Implementing Iterables
- Blocking a asynchronous function calls.
How we can create the generators ?
For creating a generators we need four components.
- function keyword.
- asterisk(*) sign, that can be added after function keyword.
- yield keyword.
- next() method.
Let’s see Syntax
Syntax 1:
//Here astrik sign after the function defines //the generators and yield keyword helpful //to create iterators in the generators var generator_name = function* () { //PERFORM SOME TASK HERE... //PERFORM SOME TASK HERE... yield [return any value]; //PERFORM SOME TASK HERE... //PERFORM SOME TASK HERE... } var genObject = generator_name(); genObject.next();
Syntax 2:
//Here astrik sign after the function defines //the generators and yield keyword helpful //to create iterators in the generators var generator_name = function* () { //PERFORM SOME TASK HERE... //PERFORM SOME TASK HERE... var ValueNeeded = yield; //PERFORM SOME TASK HERE... //PERFORM SOME TASK HERE... } var genObject = generator_name(); genObject.next(); genObject.next(10);
As you see above we created the function with following asterisk(*) sign, so now it’s called the generators and we are using the yield keyword for the create a iterators in generators.
How the generators are executing ?
Let’s understand with the simple example.
var gen = function*() { var index = 0; document.write(index + " THIS IS FIRST LINE"); yield index++; document.write(index + " THIS IS SECOND LINE"); } document.write("Genrator's object is created"); var genObject = gen(); document.write("Genrator is started"); genObject.next(); document.write("Genrator is paused"); genObject.next(); document.write("Genrator is finished"); //Genrator's object is created //Genrator is started //0 THIS IS FIRST LINE //Genrator is paused //1 THIS IS SECOND LINE //Genrator is finished
Steps:
- First we created the generators (using the function and asterisk(*)).
- After we have to create the object of it because the it can not be executed itself.
- After that we call the next() method of it using the object we are created recently. So now what’s happen is here that execution of function is start and executing till it get the yield keyword in line of code.
- If the yield keyword is found than it stops the execution and pass the control of execution where the next() method is last called.
- If the yield keyword is not found than it executed all the line of the code of the function and return the execution control to the where the next() method is called.
- If you call the next() method one more time than the generators go to the step 3 and execute the remaining code of the function till the next yield statement is found.
Above process is continue till the all the code of the function is executed and all the yield keyword is executed. You can be skip the some yield statement by the not calling next() method more.
I know it’s too much complicated to you understand what is going there lets understand by following photo.
Now go by the above photo step by step you will get the exact idea that what is going on or how the generators are executing?
How and what the generators are return ?
So the generators returns the object with two properties value and done, it’s return the same object that returns by the Symbol.iterator.
Syntax:
{ done: [ true || false ], value: [value that we want to return] }
If you want to read more about the above object and it’s properties, click here.
But we are not creating the above object in our generators, It is automatically created and return where the next() method is called.
It’s return when the yield statement is execute in generators or at the end of the generators.
How we can access the return value of the generators ?
When we called the next() method than it give us the object with two properties that are done and value, So if you want the value than you can access like this:
var value = genObject.next().value; //or var obj = genObject.next(); var value = obj.value;
Send data to Generator by parameter and return value from the Generator
Generators can return the value as well as it allow us to send the value to the generators using the next() method, We can pass the parameter in the next() method and at the other end the yield receive that parameter and assign to the variable.
Example:
var gen = function*() { document.write("THIS IS FIRST LINE FROM GENRATOR "); var value = yield; document.write("THIS IS LAST LINE FROM GENRATOR " + value + " "); return "DONE"; } var objGenrator = gen(); objGenrator.next(); var objResult = objGenrator.next("BYE BYE!!!"); document.write("Result by GENRATOR: " + objResult.value); //THIS IS FIRST LINE FROM GENRATOR //THIS IS LAST LINE FROM GENRATOR BYE BYE!!! //Result by GENRATOR: DONE
As you see in above example that we can not pass the parameter with the first call of the next() method, So we have to call the next() method second time, because when we call the next() method first time, the generators are started the execution and stop the executing at the yield statement and when we call the next() method second time with parameter than the value will be store on the yield statement where function is stop the execution, because in the generators the yield keyword only can receive the parameter value.
So we can also say that yield keyword worked as the data consumers and data producers.
If you want to pass the parameter on the first call of the next() method than you can do that by passing the parameter at the time of the object creation.
Example:
var gen = function*(my_value) { yield my_value; } var genObject = gen("JavaScript Hive"); alert(genObject.next().value); // JavaScript Hive
Now we know the rule of the data passing in the generators that we can not be able to pass the data to the first call of next() and we want to pass the parameter in generators on the first call, so we can do the workaround that help us to send the value on the first call of the next() method.
Here workaround is nothing but we can create the one extra route means function that create the object of the generators and call the next() method one time for us and return that object.
Workaround:
function routine(genrator_function) { return function(){ var genObject = genrator_function(); genObject.next(); return genObject; }; } var gen = routine(function*() { var my_value = yield; alert(my_value); }); gen().next("JavaScript Hive"); // JavaScript Hive
Generators and Symbol.iterator
Generators can create the Symbol.iterator automatically with the help of the yield and it’s return type object. Let’s create the example of it and see the difference of it calling method.
var WordSplit = function*(string) { if( string == "" || string == undefined || string == null){ yield "Please, Pass the valid string!!!"; } else{ var wordsArray = string.split(" "); for(var i = 0; i < wordsArray.length; i++){ yield wordsArray[i]; } } } var string = "I am reading JavaScript tutorial from the JavaScriptHive.info and It is awesome!!!"; for ( var word of WordSplit(string)){ document.write(word + ""); } //I //am //reading //JavaScript //tutorial //from //the //JavaScriptHive.info //and //It //is //awesome!!!
Now if you see the above example we are not created the object of the Generator. Because here we us the for…of loop so generator create the Symbol.iterator behaviour so for…of loop can work.
Generators Method in class
We can also create the generators method in the JavaScript Classes. There is no big difference and deal to create the generator in the JavaScript Classes.
Syntax:
class ClassName{ *GenratorName() { //PERFORM TASK HERE... } } var obj = new ClassName(); obj.GenratorName.next();
As you seen in above syntax we created the generator inside the class without the function keyword. It is also one way to create the generator in any class or an object.
Now let’s convert the above string split program to class.
Example:
class StringSupport{ *WordSplit(string) { if( string == "" || string == undefined || string == null){ yield "Please, Pass the valid string!!!"; } else{ var wordsArray = string.split(" "); for(var i = 0; i < wordsArray.length; i++){ yield wordsArray[i]; } } } } var string = "I am reading JavaScript tutorial from the JavaScriptHive.info and It is awesome!!!"; var objStringSupport = new StringSupport(); for ( var word of objStringSupport.WordSplit(string)){ document.write(word + " "); } //I //am //reading //JavaScript //tutorial //from //the //JavaScriptHive.info //and //It //is //awesome!!!
Generators is playing the main three roles
- Symbol.iterator: Generators can create the Symbol.iterator and the same behaviour like it.
- Data Consume: Generator can receive the value at any point using the yield keyword using the next() method.
- Data Produce: Generator also can return the value at any point using the yield keyword and return keyword.
Please, Comment down you review about the generators.
Happy Coding...
🙂