Hello coders! π§ββοΈ
Have you ever heard of Generator Functions in JavaScript?
These were introduced in 2015, with the ES6 update and they allow you to create iterators in a more convenient and expressive way.
Generator functions have a pretty weird syntax. You can declare a generator function with the function
keyword followed by an asterisk (*
). π€
function* myGenerator() {
// generator code here
}
Note that unlike normal functions, you can't declare a generator function with arrow syntax. β οΈ
Inside a generator function, you can use the yield
statement to produce a value that can be iterated over.
The generator function's execution can be paused and resumed as needed. This makes it suitable for dealing with asynchronous operations, such as fetching data from a server.
We can call the next()
method on the generator to run the execution until the nearest yield
statement.
function* myGenerator() {
yield 1;
yield 2;
return 3;
}
const generator = myGenerator();
console.log(generator.next()); // { value: 1, done: false }
console.log(generator.next()); // { value: 2, done: false }
console.log(generator.next()); // { value: 3, done: true }
As we can see, the next()
method returns a object with two properties: value
(the value yielded in the function) and done
(true
if the function returned a value with return
instead of yield
, since it's now finished). βοΈ
// In TypeScript π¦
interface NextReturns {
value: any; // or unknown, for TypeScript lovers ;D
done: boolean;
}
Let's now see some real world examples for this strange feature! π
We could start by creating a function that generates and infinite sequence of numbers (useful when you need to assign IDs to objects or classes for example):
function* infiniteNumbers() {
let num = 1;
while (true) {
yield num++;
}
}
const numGenerator = infiniteNumbers();
console.log(numGenerator.next().value); // 1
console.log(numGenerator.next().value); // 2
console.log(numGenerator.next().value); // 3
// You can keep calling numGenerator.next() to get the next number. βΎοΈ
Generator functions can produce sequences with conditions too. For example, you can create a generator that yields a sequence of numbers from a start to a certain limit.
function* generateSequence(start, end) {
for (let i = start; i <= end; i++) yield i;
}
const sequenceGenerator = generateSequence(1, 5);
for (const value of sequenceGenerator) {
console.log(value);
}
/* 1
2
3
4
5
*/
We could use generators to create a function that automatically implements pagination with asynchronous data fetching:
async function* paginateData() {
let page = 1;
while (true) {
const data = await fetchData(page);
if (data.length === 0) break;
yield data;
page++;
}
}
const dataPaginator = paginateData();
(async () => {
for await (const chunk of dataPaginator) {
// Process and display the data chunk
console.log(chunk);
}
})();
There are a lot of other cases in which generators can be useful, but from now I'll leave playing with it to you, hoping you loved this weird feature as much as I did when I learnt it for the first time π.
Some nice resource I found if you want to dive deeper:
Who am I?
I am an Italian high-school student who is interested in web-dev π§ββοΈ. If you'd like to support me, you can follow me here and on my GitHub, I would really appreciate it π
Top comments (0)