In this post, you can learn the basics of the specs as well as a particular use case where you’ll likely to use the new techniques. Also you’ll learn about one available library which provides most of the basic operations to work with these kinds of collections effectively.
Arrays are inherently finite, as they store all the elements in memory. There is no way to construct them dynamically and they also don’t support lazy evaluation. So a construct like this will result in an infinite loop and thus infeasible:
ES6 Proxies might change this, as they add support to dynamic getters. You might think that a construct like this would result in an array containing all the natural numbers:
It indeed creates an array-like object that returns all the natural numbers, but unfortunately in practice it’s hardly usable. It is missing essential Array functions like splice; it makes them unsupported by libraries like Underscore.js. In theory, you can write utility functions like filter and map, but it’s definitely not mainstream.
We write articles like this regularly. Join our mailing list and let's keep in touch.
Then iterators came to the rescue. They allow infinite collections and even have a built-in language construct to iterate them: the for-of loop. To construct an iterable, you need to return an iterator for the Symbol.iterator key. The iterator only needs a next() method that returns an object with a done and a value keys. The former indicates whether there are more elements, and the latter contains the actual element. You can create an iterator like this:
And you can iterate over it using the for-of loop (just don’t forget to terminate it, because it’s an infinite collection!):
Generators are just syntactic sugar over iterators. Instead of writing all the boilerplate, you can concentrate at the logic. The same iterable can be created using a generator:
And you need to call it when you are iterating over it:
Why would you need infinite collections? They came handy when you don’t know how many elements you’ll need in advance. For example, calculating the sum of the first 100 positive numbers is pretty straightforward (this example uses Underscore.js):
But calculating the first 100 primes are a bit harder:
Gentoo library - Generator tools
The widely used libraries, like Underscore.js, do not support iterators. They are based on arrays and array-likes. Fortunately there are already a few projects filling the gap. It’s still early days, but they are slowly becoming mainstream. The one I’ve found quite usable is called Gentoo and it has the basic utility functions you’d need when you are working with collections, like filter, map, and reduce. The original repo seems abandoned, but feel free to use my fork, as it has some additional features like takeWhile and chaining. Just drop in the library and the babel polyfill for the generators and you’re good to go.
Despite being a relatively new and still little known technology, browser support is quite good. Chrome, Firefox, and Edge all have proper support, only Safari is lagging behind. But with compilers like Babel, you can transpile your code to ES5; just include the polyfill, as that’s required in runtime.
When you are working with infinite collections, always make sure you use an operator that limits the output. It is quite easy to make an infinite loop and break your app.
The infinite way
Using the gentoo library, the previous example can be written in a more effective and robust way:
This solution does not have any magic numbers that are error-prone, making it a more robust way. It is also effective, as there are no wasted operations.
Generators are already supported by the major browsers, and you can compile your code with Babel to use them in older ones. You can use them today without any hassle, and while their use cases are quite limited, they will certainly make your code more readable if you use them effectively.