Eager Javascript ES6 generator functions

Today I finally got a viable use case for the ES6 generator functions.

I needed to create a service which will generate cryptographic signatures asynchronously on the background. The generation might take over ten seconds depending on the device it’s ran on. It would also have to start generating me a new signature right after the previous one is yielded so it will be available as soon as possible.

First off, let’s create a service class with the generator.

export default class WorkService {

    static generator;

    static start() {
         if (!this.generator) {
             this.generator = this._generator();
         }
    }

    static async getSignature() {
        return await this.generator.next().value
    }

    static async *_generator() {
        while (true) {
            const signature = await SignatureService.generate();
            yield signature;
        }
    }

}

Here we have our WorkService. We’re calling the function start() when the user has logged in and we have all the data we need for the signing operation. This function will start the generation and should eagerly generate our first signature.

At this moment, it doesn’t. This is because the ES6 generator functions are lazy. We want the execution to be paused at the first yield keyword where we already have the signature. Currently, the execution will be paused at the function definition until we run the first next() call. But if we run it before we really need the signature, we will be throwing the first signature away – and that cannot be.

So, let’s modify.

export default class WorkService {

    static generator;

    static start() {
         if (!this.generator) {
             this.generator = this._generator();
             this.generator.next(); // Initialize the first signature on start
         }
    }

    static async getSignature() {
        const signature = await this.generator.next().value; // Get the generated signature
        this.generator.next(); // Start generating the next value
        return signature;
    }

    static async *_generator() {
        while (true) {
            const signature = await SignatureService.generate();
            yield; // Magic
            yield signature;
        }
    }

}

To get the generator to work eagerly rather than lazily, I added a next() call to the start() function to continue the function execution to the next yield keyword, but creating the signature along the way. Now we have the signature fetched before we’ve called getSignature().

When we now call the getSignature() function, the program will continue the execution to the following yield keyword. To make it start generating us a new signature right after yielding the previous one, let’s call the next() function right after getting the signature out.

 

Miro Metsänheimo

A software developer from Finland born in -92. I'm passionate about computers and technology. Feel free to message me about anything!

 

Leave a Reply

Share On Facebook
Share On Twitter
Share On Google Plus
Share On Linkdin