Iterator Helpers добавляют к итераторам
map, filter, take, reduce, toArray и другие методы в стиле массивов. Это полезно в API clients, Node.js-сервисах, SSR и build tooling, но частая ошибка - воспринимать iterator pipeline как переиспользуемую коллекцию.Ленивость вместо временных массивов
const emails = users
.values()
.filter(user => user.active)
.map(user => user.email)
.take(10)
.toArray();
Здесь не создаются массивы после
filter и map. Элементы проходят цепочку по одному: user -> filter -> map -> take.Это выигрывает, когда данных много, нужен только префикс результата или источник потенциально бесконечный:
function* numbers() {
let i = 0;
while (true) yield i++;
}
const result = numbers()
.filter(n => n % 2 === 0)
.map(n => n * n)
.take(5)
.toArray();Подводный камень: итератор одноразовый
const iterator = [1, 2, 3]
.values()
.map(x => x * 2);
iterator.toArray(); // [2, 4, 6]
iterator.toArray(); // []
Это не баг, а модель курсора. Если часть данных уже прочитана через
next(), пайплайн продолжит с текущей позиции.Практический совет
Не передавайте iterator pipeline как “коллекцию” между модулями:
const activeUsers = users
.values()
.filter(user => user.active);
sendEmails(activeUsers);
renderUsers(activeUsers); // может быть пусто
Если результат нужен несколько раз, материализуйте его:
const activeUsers = users
.values()
.filter(user => user.active)
.toArray();
Или отдавайте фабрику нового итератора:
const activeUsers = () =>
users.values().filter(user => user.active);
Терминальные операции запускают проход
map, filter, take ленивые. toArray, reduce, forEach, some, every, find реально потребляют итератор.Вывод:
Iterator Helpers хороши для читаемых и экономных пайплайнов, но надежная архитектура требует явно решать, где итератор одноразовый, а где нужна материализованная коллекция.
