Visualizing Process with Javascript ES6 Generators

elliot

Elliot

Posted on June 7, 2019

Visualizing Process with Javascript ES6 Generators

Countless hours are poured into designing functions that run in the fraction of a second. When functions execute so quickly, their ingenious implementations are not easily appreciated. Let’s slow them down, and take the necessary time to watch them work.

In this article, I go over the basics of generator functions and how to use them to visualize a function’s process.

What's a Generator Function?

Generator functions are new to JavaScript, and many people have been struggling to find real-world practical uses for them. I’m excited to show you a cool way to use them, but let’s go over the basics first. Here’s a simple Generator function:

function * myGeneratorFunction(arg) {
        yield 1;
        yield arg;
}
Enter fullscreen mode Exit fullscreen mode

It looks a lot like a normal function except for two differences: an asterisk (*) after function, and the use of the yield statement.

Below is how myGeneratorFunction is used:

const generator = myGeneratorFunction('hello world');

console.log(generator.next().value)
// logs out 1

console.log(generator.next().value)
// logs out 'hello world'
Enter fullscreen mode Exit fullscreen mode

Calling a Generator Function does not execute it right away, instead it returns a Generator object. Calling .next() on the Generator object causes myGeneratorFunction to execute up to the first yield statement, returning the value appearing after the yield keyword. Generators allow us to stop and start the execution of a function. Check out the the MDN page on Generators for more information.

Why visualize a function's process anyway?

Visualizing a function’s process helps when trying to understand the implementation, and can result in fascinating animations and impressive effects. Take this video visualizing various sorting algorithms for example:

This video illustrates why process visualization is awesome:

  • Watching the process of sorting is strangely captivating.
  • The differences in how each sorting algorithm works are instantly obvious.
  • What better way to interest someone in how something works, than to make how it works look cool?

Let's visualize!

Computers nowadays run ridiculously, faster-than-Usain-Bolt, mind-bogglingly fast. That means that functions run just as fast. With a Generator we can slow down the function process so that it operates at 60 steps per second. At this speed we can watch a function do what it does best, in real time as it does it. It will be like watching the world’s fastest sprinter in slow motion, seeing individual muscles contract and relax in a single step.

For our example let's shamelessly copy the youtube video above and visualize the insertion sort algorithm with a bar graph. Below are two pieces of code we will need. One for the basic algorithm, and one for drawing a bar graph. After these pieces of code, we'll see how to easily put them together.

This is the basic insertion sort algorithm implementation:

function insertionSort(inputArray) {
    for (let i = 0; i < inputArray.length; i++) {
        const value = inputArray[i];

        let j = i - 1;
        while (j >= 0 && value < inputArray[j]) {
            inputArray[j+1] = inputArray[j];
            j -= 1;
        }
        inputArray[j+1] = value
    }
    return inputArray;
}
Enter fullscreen mode Exit fullscreen mode

And below we have a function that draws an array as a bar graph on a canvas. I use the 2d Canvas API:

const c = document.getElementById('canvasEl');
const ctx = c.getContext('2d');

function drawGraphFromArray(array) {
    ctx.clearRect(0,0,c.width,c.height);
    const barWidth = c.width / array.length;
    const barHeightScale = c.height / Math.max(...array);

    array.forEach((value, i) => ctx.fillRect(
        i * barWidth,
        0,
        barWidth,
        barHeightScale * value
    ));
}
Enter fullscreen mode Exit fullscreen mode
draws a bar graph where x axis: index in the array, y axis: value at index

Now back to our regular programming. In order to slow down our insertion sort function we are going to rewrite it as a Generator function. Sounds tricky, right? It’s actually the opposite of tricky, it’s SUPER EASY. This is the rewritten insertion sort:

function * insertionSort(inputArray) {
    for (let i = 0; i < inputArray.length; i++) {
        const value = inputArray[i];

        let j = i - 1;
        while (j >= 0 && value < inputArray[j]) {
            inputArray[j+1] = inputArray[j];
            j -= 1;
            yield inputArray;
        }
        inputArray[j+1] = value
    }
    return inputArray;
}
Enter fullscreen mode Exit fullscreen mode

There are only two changes. We add an * after the function keyword and add a yield statement whenever we want to draw a frame in the animation, yielding the array being sorted. With those simple changes, we’ve converted a function into a Generator function that is executed one step at a time, and yields the data we need to visualize its process. This rewrite is great because it’s unintrusive - there’s almost no chance the conversion will affect the logic of the function.

Now let’s put drawGraphFromArray and our new insertionSort Generator function together in a requestAnimationFrame render loop.

// code from above ...

const randomArr = Array(50).fill(0).map(Math.random);
const sortGenerator = insertionSort(randomArr);

function renderLoop() {
    const yieldedArray = sortGenerator.next().value;

    drawGraphFromArray(yieldedArray);

    requestAnimationFrame(renderLoop);
}
renderLoop();
Enter fullscreen mode Exit fullscreen mode

resulting in our finished animation:

In the final animation above, we see the bar graph go from a jagged mess to a beautiful staircase. To achieve this, we ask our insertion sort to operate at one step per render loop with .next(). requestAnimationFrame makes sure our render loop runs at 60 frames per second, the perfect speed for a smooth animation.

Insertion sort is a simple example of what we can do...

This article was originally published on my blog http://elliot.website/a/?Visualizing%20Process%20with%20ES6%20Generators. Check it out to see some bonus content about creative coding using generators.

Thanks for reading. What's a creative way you've used generator function?

💖 💪 🙅 🚩
elliot
Elliot

Posted on June 7, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related