Generators (NodeJS Iterators)

Blocking code on a non-blocking programming language (sort of)

·

3 min read

function* setNextTurn(players: Player[]) {
  let i = 0;
  const playersLen = players.length;
  while (true) {
    const a: string = yield players[i].id;
    i++;
    if (i === playersLen) {
      i = 0;
    }
  }
}

I guess I'll be writing a blog weekly (hopefully). There's a lot I have learned recently and it would be really useful to document these. At the moment, I don't have so much use with them so I'm bound to forget them. Blogging these would prove to be useful later on.

Generators. It is one of the newest features of Javascript and one of those that scare me TBH. It sounds so technical and hard. But yeah, in a nutshell, a generator object (yes, it is an object) is something that a generator function returns.

Generator functions are really just functions, albeit fancy ones. Sadly, it turns out that you can't declare one through the arrow notation though.

What sets generator functions apart from other functions is really just the way it is declared and that we can use the yield keyword inside it.

They are declared with the old but gold way of declaring functions but suffixing it with an asterisk,

function* firstGenerator() {
  yield "Yey, you got a generator!";
}

Now, what does the yield keyword does? Well, the yield keyword is what makes a generator useful, the same way how the await keyword is to async functions.

At its core, javascript is a non-blocking programming language. Now, to write blocking code (sort of), generators are introduced. Technically, using the yield keyword just tells javascript until which part of the code to execute on a Generator.next() call. You can declare as many yield keywords as you like on a generator function. Look at the following code,

function* secondGenerator() {
  console.log("Hi ho from the generator!");
  yield;
  console.log("Hey hey from generator!");
  yield "oh, it's not that hard.";
}

const sg = secondGenerator();
sg.next();
// Hi ho from the generator!
console.log(sg.next().value);
// Hey hey from generator!
// oh, it's not that hard.

Let's analyze the calling of the secondGenerator function line by line.

First, the secondGenerator function is executed and the generator object produced is assigned to the sg variable. Notice that no code line is executed inside the secondGenerator function yet.

Going on, sg.next() is then called. Notice now that console.log("Hi ho from the generator!") is executed but not the console log after that. The code until the first yield keyword declaration is executed.

Going further, sg.next().value is called inside a console log. Now, the console.log("Hey hey from generator!") code line is fired and the string that came after the yield keyword yield "oh, it's not that hard." is printed. There are quite a few things here, yield keyword could be supplied with a prefix and a suffix (or either of them).

When a suffix is supplied, it is like assigning a value to the value field of the object returned by the Generator.next() call. Every Generator.next() call returns an object with the fields value and done. Where done is a boolean and the value is whatever you provided to the yield keyword as a suffix.

This is where I'll end the blog. I purposely left the use case where the yield keyword is provided a prefix because I can't get a good grasp of it yet. It should be the topic of the next blog.

To be continued...