JavaScript

Asynchronous Iterators vs Asynchronous Generators in JavaScript

You may find yourself in a situation where it is required to immediately process some sequential events rather than waiting until all of the events are generated, for instance, receiving data over a network where one packet is fetched at a time. In such a situation, JavaScript libraries such as RxJS can assist in handling the asynchronous data; however, they also put additional overhead regarding the code complexity and the cognitive effort required to master them.

In JavaScript, Asynchronous Iterators and Asynchronous Generators offer the same functionality that could be effectively implemented using the JavaScript language primitives. So, why not choose a simple solution rather than put yourself in another confusion?

This post discusses Asynchronous Iterators vs Asynchronous Generators in JavaScript along with suitable examples. So, let’s start!

Iterators in JavaScript

In JavaScript, “Iterators” are used to access synchronous data structures such as arrays, maps, and sets. They are primarily based on the “next()” method, which comprises two properties: “next” and “value”:

  • The “value” property of the next() method indicates the current value in the iteration sequence.
  • The “done” property of the next() method represents the iteration status, where “false” indicates that the iteration process is completed and “true” signifies that iteration is incomplete.

Now, we will check out the working of iterators in JavaScript with the help of an example.

Example: Using Iterators in JavaScript

We will create a “numbers” object having two properties: “start” and “end”. Then, we will add an “iteration ability” to the “numbers” object by utilizing the “Symbol.iterator()” method.

The “Symbol.iterator()” method will be invoked once, at the beginning of the “for..of” loop, and returns an iterable object. After performing this operation, the “for..of” loop will access the iterable object and fetch the values in the iteration sequence:

let numbers = {
    start: 1,
    end: 4,
    [Symbol.iterator]() {
        return {
            current: this.start,
            last: this.end,
            next() {
                if (this.current <= this.last) {
                    return { done: false, value: this.current++ };
                } else {
                    return { done: true };
                }
            }
        };
    }
};

The above-given, “next()” method will be invoked and return the “value” as an object:

for(let value of numbers) {

alert(value);

}

Write out the provided code in the console window and execute it:

We have successfully iterated over each element of the “numbers” object which can be seen in the following gif:

As mentioned earlier, regular JavaScript iterators can help you iterate over the synchronous data. What if the values come asynchronously because of any delay? In such a scenario, you must implement the Asynchronous Iterators in JavaScript.

Asynchronous Iterators in JavaScript

The Asynchronous Iterators are embedded in ES9 to handle the asynchronous data sources. It works similar to the regular iterator except that the “next()” method in an asynchronous iterator returns a “Promise” that resolves the “value” and “done” properties values of an object.

Convert Regular Iterator to Asynchronous Iterator in JavaScript

If you want to convert a regular iterator to an Asynchronous iterator, then follow the below-given instructions:

  • Instead of using the “Symbol.Iterator()” method, utilize “Symbol.asyncIterator()”.
  • Force the “next()” method to return a Promise and add an “async” keyword with it as: “async next()”.
  • Lastly, the “for await..of” loop can be used to iterate over an object, instead of the “for..of” loop.

Example: Asynchronous Iterators in JavaScript

We will now convert the regular iterator defined in the previous example to Asynchronous Iterators by following the specified rules.

For this purpose, we will replace the “Symbol.Iterator()” with the “Symbol.asyncIterator()” method. Then, we will add the keyword “async” before the “next()” method. Using “await” in the “next()” method will set the time for fulfilling the Promise after “2” seconds:

let numbers = {
    start: 1,
    end: 4,
    [Symbol.asyncIterator]() {
        return {
            current: this.start,
            last: this.end,
            async next() {
                awaitnewPromise(resolve => setTimeout(resolve, 2000));
                if (this.current <= this.last) {
                    return { done: false, value: this.current++ };
                } else {
                    return { done: true };
                }
            }
        };
    }
};

For iteration over an asynchronous iterable object, the “for await..of” loop will be utilized in the following way:

(async () => {
  for await (let value of numbers) {
    alert(value);}
})()

The output will display the iterated values in the alert box after a delay of two seconds:

By this point, you have understood the working of Asynchronous Iterators. Now, we will move ahead and learn about Asynchronous Generators in JavaScript.

Generators in JavaScript

Iterators in JavaScript are quite useful; however, they need careful programming to perform their expected functionality. The JavaScript Generator function is another powerful tool that permits you to define an iterative algorithm with the help of a single “non-continuous” function.

Initially, a Generator function does not execute its code when it is invoked; instead, it returns a specific type of iterator known as “Generator”. The Generator function can be invoked as many times as needed, and on each call, it returns a new “Generator,” which can be iterated once.

To write the Generator function, the “function*” syntax is used. This function also comprises a “yield” operator that pauses the Generator function’s execution until the next value of an object is requested.

Example: Using Generators in JavaScript

We will define a “generator” function that returns the values from a “startingPoint” to “endingPoint” using the “yield” operator. The “*” added with the “function” keyword indicates that “generator()” is a Generator function, not a normal regular function.

function* generator(startingPoint, endingPoint) {
    for (let i = startingPoint; i<= endingPoint; i++) {
        yield i;
    }
}

In the next step, we will invoke the “generator()” function which returns a Generator stored in the “x” object:

let x = generator(1, 5);

Lastly, to iterate over the “x” generator, we will use the “for..of” loop:

for (const num of x) {

     console.log(num);

}

Execution of the provided program will show the iterated values:

If you want to retrieve Promise based results from the “Generator“, you have to use “Asynchronous Generator” in the JavaScript program.

Asynchronous Generators in JavaScript

Asynchronous Generator in JavaScript works similar to the Generator function except that the “next()” method in Asynchronous Generator returns a “Promise” that resolves the “value” and “done” properties values of an object.

Convert Generator Function to Asynchronous Iterator in JavaScript

Follow the below-given instructions to convert a Generator function to an Asynchronous Iterator in JavaScript:

  • Use “async” before the “function*” keyword.
  • Instead of a “value”, “yield” should return a “Promise”.

Now, we will show you the practical procedure for converting a Generator function into Asynchronous Generators in JavaScript.

Example: Asynchronous Generators in JavaScript

First of all, we will add the “async” keyword before defining the “asyncSequence()” Asynchronous function. The asyncSequence() yields a “Promise” which will be fulfilled in one second:

asyncfunction* asyncSequence(startingPoint, endingPoint) {
    for (let i = startingPoint; i  {
            setTimeout(() => {
                resolve(i);
            }, 1000);
        });
    }
}

Lastly, “for await..of” loop is used to iterate over and return the Asynchronous Generator:

(async () => {
    let x = asyncSequence(1, 5);
    for await (let num of x) {
        console.log(num);
    }
})();

This JavaScript program will return values from “1” to “5” while taking a gap of “one” second:

We have provided the essential information related to Asynchronous Iterators and Asynchronous Generators. Both of them can be used for iterating over asynchronous data in JavaScript, however; It can be challenging for beginners to maintain the internal logic or definition of the Asynchronous Iterators, whereas the Asynchronous Generators offers a more efficient and less error-prone way of utilizing iterators. It also hides the iterator’s complexity and makes code concise and readable.

So, we recommend you use Asynchronous Generators to handle iterations related to asynchronous data collection.

Conclusion

Asynchronous Iterators and Asynchronous Generators are utilized to iterate over the data, provided after a certain amount of time. The Asynchronous Iterators execute the “Symbol.asyncIterator()” method to return an “iterator”, whereas the Asynchronous Generators return a special type of iterator “Generator” by itself, which can be used wherever the iteration is required. This write-up discussed Asynchronous Iterators and Asynchronous Generators in JavaScript.

About the author

Sharqa Hameed

I am a Linux enthusiast, I love to read Every Linux blog on the internet. I hold masters degree in computer science and am passionate about learning and teaching.