DEV Community

Alessandro Foglia
Alessandro Foglia

Posted on

Unlocking the Power of JavaScript Generators 🦾⏭️

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
}
Enter fullscreen mode Exit fullscreen mode

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 }
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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. ♾️
Enter fullscreen mode Exit fullscreen mode

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 
*/
Enter fullscreen mode Exit fullscreen mode

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);
  }
})();
Enter fullscreen mode Exit fullscreen mode

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)