JavaScript Array Lazy Evaluation Through Iterator Helper
Introduction
Previously mentioned JavaScript’s Iterator Protocol: What makes JavaScript Iterables Iterable?, and arrays, being based on iterators, naturally benefit from the recently launched iterator helper for lazy evaluation.
What are the shortcomings of eager evaluation array methods?
For array methods like map, filter, slice, they allow for intuitive chaining of data handling, but they perform eager evaluation, creating a new array with each operation. This is not a big issue for small datasets, but when dealing with large datasets or streams, the repeated creation and copying can become quite costly.
const arr = [1, 2, 3].map(x => x * 2).filter(x => x > 2);// Both map and filter immediately create new arraysWhat are the benefits of using Iterator Helpers for lazy evaluation?
Better efficiency and space utilization
In the new Iterator Helpers proposal, arrays can create an iterator using .values(), which allows values to be accessed lazily as the iterator is consumed. This means that each element is only processed when “consumed,” and intermediate results are not created ahead of time.
const iter = [1, 2, 3, 4, 5].values() .map(x => x * 2) .filter(x => x > 5)
console.log([...iter]); // [ 6, 8, 10 ]// For example, only executed when expanded [...] or using for...ofEach method of Iterator Helpers only returns a new iterator, does not produce intermediate arrays, and does not pre-compute all values, allowing for simple conversion back to an array via toArray or spread syntax.
Lazy evaluation results in fewer computations
For example, to find the top 5 products with over 50% discount from 100,000 entries:
const topDiscounted = products .filter(p => p.discount > 0.5) // Iterates through all 100,000 entries .slice(0, 5); // Then take the top 5Even though theoretically, computation can stop after finding 5 products that meet the condition, eager evaluation means we still have to iterate through all data. Using the mindset of lazy evaluation can significantly reduce the needed computation:
const topDiscounted = products .values() // Convert to iterator .filter(p => p.discount > 0.5) // Filter step by step .take(5); // Stop once finding the top 5 that meet the condition
console.log([...topDiscounted]);Conclusion
| Comparison | Array Methods | Iterator Helpers |
|---|---|---|
| Data Structure | Array (eager) | Iterator (lazy) |
| Computation Method | Creates intermediate arrays | Processes item by item |
| Typical Use | Small to medium data processing | Large data or stream processing |