([1, 2, 3, 4, 5, 6]) .filter(v => v % 2 === 0) .forEach(v => console.log(v))
Here we have an array of numbers, extracted for its even numbers, and printed to the console. Notice that we have an array of numbers which are predefined and thus loaded onto memory. Now imagine if the array wasn't just 5 numbers. Ignore the
forEach at this point, what if it contained a million records of grocery purchase information? Loading that much data into memory all at once can potentially starve the system of memory and crash the app.
That's where iterators and iterables come in.
Iterators are objects that implement the iterator protocol (i.e. in typed language terms, an interface). Iterators are objects with a
next()method that return an object containing
doneproperties. These define the current iteration value and the iterator state, respectively.
Iterables are objects that define their iteration behavior by defining an iterator stored in a property whose key is
The key piece of functionality that wooshed over my head all this time is that with iterables, you execute a piece of code to return the value of an item. Iterables are objects that have no idea about its items, and has to ask its iterator for values. And since an iterator is arbitrary code, we are in full control of what the value is, where the value comes from, when we load the value into memory, and how we fetch the value. This means we can:
- Represent a dataset as an object without loading all the data into memory.
- Fetch values as needed instead of loading everything into memory at once.
- Avoiding loading unneeded data (e.g. if we
breakthe loop midway).
- Consuming the iterable separately from its declaration (lazy evaluation).
- Create array-like objects without array prototype hacks (e.g. jQuery objects).
- Change the values on the fly depending on the iterator state.
- Fetch data from any source besides memory (e.g. filesystem, network, etc.).
- Optimize storage and retrieval by using custom data structures and algorithms.
- And so much more!
While I use the built-in iterables a lot on a daily basis, I've yet to understand the full power of iterables and what else it's capable of. In fact, I just learned that async iterators exist and
for await...of is a thing. This means we can loop through iterables whose backing data source is asynchronous, like a network call, or another thread, or some throttled operation!
My mind is blown.