Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Array-Like Methods

Enumerable gives you the Array methods you know and love, but for async data.

Transformations

map()

Transform each item:

const doubled = await enumerate([1, 2, 3])
  .map(n => n * 2)
  .collect();
// [2, 4, 6]

Works with async functions:

const results = await enumerate(urls)
  .map(async (url) => {
    const response = await fetch(url);
    return response.json();
  })
  .collect();

filter()

Keep only items that match:

const evens = await enumerate([1, 2, 3, 4])
  .filter(n => n % 2 === 0)
  .collect();
// [2, 4]

flatMap()

Map and flatten in one step:

const words = await enumerate(["hello world", "foo bar"])
  .flatMap(line => line.split(" "))
  .collect();
// ["hello", "world", "foo", "bar"]

Aggregations

reduce()

Combine items into a single value:

const sum = await enumerate([1, 2, 3, 4])
  .reduce((acc, n) => acc + n, 0);
// 10

Build complex objects:

const grouped = await enumerate(items)
  .reduce((acc, item) => {
    acc[item.category] = acc[item.category] || [];
    acc[item.category].push(item);
    return acc;
  }, {});

count()

Count items:

const total = await enumerate([1, 2, 3]).count();
// 3

some()

Check if any item matches:

const hasError = await enumerate(lines)
  .some(line => line.includes("ERROR"));

every()

Check if all items match:

const allPositive = await enumerate([1, 2, 3])
  .every(n => n > 0);

Finding Items

find()

Find first match:

const match = await enumerate([1, 2, 3, 4])
  .find(n => n > 2);
// 3

first

Get first item:

const first = await enumerate([1, 2, 3]).first;
// 1

last

Get last item:

const last = await enumerate([1, 2, 3]).last;
// 3

nth()

Get item at index:

const third = await enumerate([1, 2, 3, 4]).nth(2);
// 3 (zero-indexed)

Slicing

take()

Take first N items:

const first3 = await enumerate([1, 2, 3, 4, 5])
  .take(3)
  .collect();
// [1, 2, 3]

drop()

Skip first N items:

const rest = await enumerate([1, 2, 3, 4, 5])
  .drop(2)
  .collect();
// [3, 4, 5]

slice()

Get a range:

const middle = await enumerate([1, 2, 3, 4, 5])
  .slice(1, 4)
  .collect();
// [2, 3, 4]

Iteration

forEach()

Process each item:

await enumerate([1, 2, 3]).forEach(n => {
  console.log(n);
});

for-await

Use standard JavaScript iteration:

for await (const item of enumerate([1, 2, 3])) {
  console.log(item);
}

Collecting

collect()

Gather all items into an array:

const array = await enumerate([1, 2, 3]).collect();
// [1, 2, 3]

toArray()

Alias for collect():

const array = await enumerate([1, 2, 3]).toArray();

Utilities

enum()

Add indices to items:

const indexed = await enumerate(["a", "b", "c"])
  .enum()
  .collect();
// [["a", 0], ["b", 1], ["c", 2]]

Use with map:

const numbered = await enumerate(["a", "b", "c"])
  .enum()
  .map(([item, i]) => `${i + 1}. ${item}`)
  .collect();
// ["1. a", "2. b", "3. c"]

tee()

Split into multiple streams:

const [stream1, stream2] = enumerate([1, 2, 3]).tee();

const [sum, product] = await Promise.all([
  stream1.reduce((a, b) => a + b, 0),
  stream2.reduce((a, b) => a * b, 1),
]);

flatten()

Flatten nested iterables:

const flat = await enumerate([[1, 2], [3, 4]])
  .flatten()
  .collect();
// [1, 2, 3, 4]

Concurrent Operations

concurrentMap()

Map with controlled concurrency:

const results = await enumerate(urls)
  .concurrentMap(async (url) => {
    return await fetch(url);
  }, { concurrency: 5 })
  .collect();

Results are returned in order.

concurrentUnorderedMap()

Map with maximum concurrency:

const results = await enumerate(urls)
  .concurrentUnorderedMap(async (url) => {
    return await fetch(url);
  }, { concurrency: 5 })
  .collect();

Results are returned as they complete (faster).

Chaining Examples

Complex Pipeline

const result = await enumerate(data)
  .filter(item => item.active)
  .map(item => item.value)
  .filter(value => value > 0)
  .map(value => value * 2)
  .take(10)
  .collect();

Real-World Example

const topErrors = await read("app.log")
  .lines
  .filter(line => line.includes("ERROR"))
  .map(line => {
    const match = line.match(/ERROR: (.+)/);
    return match ? match[1] : line;
  })
  .reduce((acc, error) => {
    acc[error] = (acc[error] || 0) + 1;
    return acc;
  }, {});

Performance Tips

Use Streaming

Don't collect if you don't need to:

// ❌ Loads everything
const items = await enumerate(huge).collect();
for (const item of items) process(item);

// ✅ Streams
for await (const item of enumerate(huge)) {
  process(item);
}

Use take() for Limits

// Get first 10 matches
const matches = await enumerate(data)
  .filter(predicate)
  .take(10)
  .collect();

Use concurrentMap() for I/O

// Process 5 URLs at a time
const results = await enumerate(urls)
  .concurrentMap(fetch, { concurrency: 5 })
  .collect();

Next Steps