# JavaScript [Iterators][] and [AsyncIterators][] for all! [![Build Status](https://travis-ci.org/leebyron/iterall.svg?branch=master)](https://travis-ci.org/leebyron/iterall) [![Coverage Status](https://coveralls.io/repos/github/leebyron/iterall/badge.svg?branch=master)](https://coveralls.io/github/leebyron/iterall?branch=master) ![710 bytes minified and gzipped](https://img.shields.io/badge/min%20gzip%20size-757%20B-blue.svg) `iterall` provides a few crucial utilities for implementing and working with [Iterables][iterators], [Async Iterables][asynciterators] and [Array-likes][array-like] in all JavaScript environments, even old versions of Internet Explorer, in a tiny library weighing well under 1KB when minified and gzipped. This is a library for libraries. If your library takes Arrays as input, accept Iterables instead. If your library implements a new data-structure, make it Iterable. When installed via `npm`, `iterall` comes complete with [Flow][] and [TypeScript][] definition files. Don't want to take the dependency? Feel free to copy code directly from this repository. ```js // Limited to only Arrays 😥 if (Array.isArray(thing)) { thing.forEach(function (item, i) { console.log('Index: ' + i, item) }) } // Accepts all Iterables and Array-likes, in any JavaScript environment! 🎉 var isCollection = require('iterall').isCollection var forEach = require('iterall').forEach if (isCollection(thing)) { forEach(thing, function (item, i) { console.log('Index: ' + i, item) }) } // Accepts all AsyncIterators, in any JavaScript environment! ⏳ var forAwaitEach = require('iterall').forAwaitEach forAwaitEach(thing, function (item, i) { console.log('Index: ' + i, item) }).then(function () { console.log('Done') }) ``` ## Why use Iterators? For most of JavaScript's history it has provided two collection data-structures: the `Object` and the `Array`. These collections can conceptually describe nearly all data and so it's no suprise that libraries expecting lists of things standardized on expecting and checking for an Array. This pattern even resulted in the addition of a new method in ES5: [`Array.isArray()`][isarray]. As JavaScript applications grew in complexity, moved to the [server][nodejs] where CPU is a constrained resource, faced new problems and implemented new algorithms, new data-structures are often required. With options from [linked lists][linked list] to [HAMTs][hamt] developers can use what is most efficient and provides the right properties for their program. However none of these new data-structures can be used in libraries where an `Array` is expected, which means developers are often stuck between abandoning their favorite libraries or limiting their data-structure choices at the cost of efficiency or usefulness. To enable many related data-structures to be used interchangably we need a _[protocol][]_, and luckily for us ES2015 introduced the [Iteration Protocols][iterators] to describe all list-like data-structures which can be iterated. That includes not just the new-to-ES2015 [Map][] and [Set][] collections but also existing ones like [arguments][], [NodeList][] and the various [TypedArray][], all of which return `false` for [`Array.isArray()`][isarray] and in ES2015 implement the [Iterator protocol][iterators]. While Iterators are defined in ES2015, they _do not require_ ES2015 to work correctly. In fact, Iterators were first introduced in 2012 in [Firefox v17](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#Iterator_property_and_iterator_symbol). Rather than using [`Symbol.iterator`][symbol.iterator], they used the property name `"@@iterator"` (in fact, the ECMAScript spec still refers to well-known `Symbols` using this `@@` shorthand). By falling back to use `"@@iterator"` when `Symbol.iterator` is not defined, Iterators can be both safely defined and used by _any version of JavaScript_. Not only were Iterables defined in ES2015, they were also implemented by the built-in data-structures including [Array][array#@@iterator]. Older JavaScript environments do not implement `Array.prototype[@@iterator]()`, however this is only a minor problem. JavaScript has another related and much older protocol: [Array-like]. A value is "Array-like" if it has a numeric `length` property and indexed access, but does not necessarily have methods like `.push()` or `.forEach()`. Much like [`Array.from`][array.from], `iterall`'s `forEach()` and `createIterator()` methods also accept collections which are not Iterable but are Array-like. This means that `iterall` can be used with [Array][], [arguments][], [NodeList][], [TypedArray][] and other Array-like collections regardless of the JavaScript environment. When libraries only accept Arrays as input, they stick developers with a tough choice: limit which data-structures can be used or limit the ability to use that library. Accepting Iterables removes this false dichotomy, and allows libraries to be more generally useful. There's no need to limit to ES2015 environments and bleeding-edge browsers to accept `Iterable`. Only using Arrays can limit the efficiency and usefulness of your application code, but custom data-structures can often feel like a fish out of water in JavaScript programs, only working with code written specifically for it. Protocols like `Iterable` helps these new data-structures work with more libraries and built-in JavaScript behavior. There's no need to limit to ES2015 environments and bleeding-edge browsers to implement `Iterable`. ## Why use AsyncIterators? In the same way that `Iterator` provides a common interface for accessing many different kinds of data-structures, `AsyncIterator` provides a common interface over an asynchronous sequence of values (similar to Stream or Observable). Async Iterators are not yet an official part of JavaScript, however they're a "Stage 3" proposal to be added, and browser vendors are [working on adding support](https://bugs.chromium.org/p/v8/issues/detail?id=5855). However, Async Iterators can be both safely defined and used today by _any version of JavaScript_, by using the utilities in `iterall`. ## FAQ > Aren't Iterables slower than Arrays? I want the highest performance possible. Arrays _are_ Iterables. Iterable is a protocol that Arrays adhere to in ES2015. It's true that creating an Iterator and stepping through it can present some overhead compared to a simple for-loop or `array.forEach`. However `iterall`'s `forEach` will delegate directly to `array.forEach` and will use a for-loop for Array-like objects, ensuring the best performance for Arrays while still maintaining support for all Iterables. > Should my library functions also return Iterables instead of Arrays? Won't > that be limiting? That could definitely be limiting if you return some generic Iterable where you could have returned an Array, and (depending on context) I wouldn't recommend you stop returning Arrays from functions if that's what you're doing today. However if your functions are returning some collection data-structure that is _not_ an Array, you should certainly consider having them implement the Iterable protocol so they can be more widely useful. Here are a few examples: In [React][], render functions are expected to return view trees, where any node (e.g. a `