In the last blog, we were talking about Iterators and the pros and cons of it. So in this blog, we will be looking at Generators and how it is “better” than Iterators.
The Generator
object is returned by a generator function and it conforms to both the iterable protocol and the iterator protocol.
It’s better than iterators in that Generator functions provide a powerful way to define an iterative algorithm by writing a single function whose execution is not continuous.
Generator functions are written using the function*
syntax.
When called, generator functions return a special type of iterator, called a Generator. Whennext
method gets called on the Generator, the Generator function executes until it encounters the yield
keyword.
The function can be called as many times as desired, and returns a new Generator each time. However each Generator may only be iterated once.
See below an infinite loop Generator:
function* infinite() {
let index = 0;
while (true) {
yield index++;
}
}
const generator = infinite(); // "Generator { }"
console.log(generator.next().value); // 0
console.log(generator.next().value); // 1
console.log(generator.next().value); // 2
// ...const newGenerator = infinite();console.log(newGenerator.next().value); // 0
console.log(newGenerator.next().value); // 1
console.log(newGenerator.next().value); // 2
To get the value using for...of
loop:
for(let value of generator) {
console.log(value); // 0,1,2
}
Accessing it using spread syntax:
[ …generator]; // 0, 1,2
Since Generator returns an iterator (noting the calling of next()
). The result of next()
is always an object with two properties:
value
: the yielded value.done
:true
if the function code has finished, otherwisefalse
.
How do we reach the last item in the iterator?
Well, each time a yield is encountered it measn the done
is set to false
. So to get the last item with done
set to true
, we use return
keyword (Any yield after this return is ignored).
function * definite() {
yield 0;
yield 1;
return 2; // Generator ends.
}
Also note that a generator object is both an iterator and an iterable.
function * generatorExample() {
yield 0;
yield 1;
return 2;
}console.log(typeof generatorExample.next);
// "function", because it has a next method, so it's an iteratorconsole.log(typeof generatorExample[Symbol.iterator]);
// "function", because it has an @@iterator method, so it's an iterable
The yield is a magical keyword that can do more things other than simply return a value and next() can do more things aside from retrieving the value.
- passing argument to next()
The argument passed to next() will be received by yield
:
function *gen(x){
yield x
return
}const generator = gen(2)
gen.next() //{value: 2, done: false}
gen.next() //{ value: undefined, done: true}
- passing a function to yield
Apart from returning values yield can also call function.
function *gen(x){
yield func()
return
}function func (){
return "function called"
}const generator = gen()
gen.next() //{value: "function called", done: false}
gen.next() //{ value: undefined, done: true}
- delegating to another generator or iterable using
yield*
expression
function* gen() {
yield 3;
}function* func() {
yield* gen();
}const iterator = func();
iterator.next().value; // 3
- async generators
To asynchronously generates a list of values (e.g. continuous calls to api), we can create an asynchronous generator.
async function* apiCall(start, end) {
for (let i = start; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 1000));
yield i;
}
}(async () => {
let generator = apiCall(1, 5);
for await (let value of generator) {
alert(value); // 1, 2, 3, 4, 5
}
})();
You can also chain the Promise:
generator.next().value.then(n => console.log(n)) // 1,2,3,4,5
In general, Generators are a special kind of Iterators using yield
keyword and implementing iteration protocols. It is really useful in Lazy Evaluation as the value can be retrieved on demand and thus memory efficient.
There’s more to cover on Generator. I found resources on MDN very useful to get the basic right, so is reading python related concepts such as .
That is so much of it!
Happy Reading!