Что такое…

Цикл for или map — что выбрать, и почему await внутри map не ждёт

Иллюстрация: две ленты конвейера — на одной рука собирает вещи в мешок, на другой каждая коробка выходит обновлённой

Ты просишь ИИ: «отправь письмо каждому пользователю из списка, по очереди». Он пишет аккуратный users.map(async user => await send(user)). Выглядит так, будто письма уходят по одному. На деле все сто улетают разом, и почтовый сервис блокирует тебя за спам.

map не умеет ждать. А обычный цикл умеет. Это лишь одно из отличий — разберём все, что важны на практике, и в конце вынесем честный вердикт.

Что делают for и map

Оба перебирают массив — берут элементы по одному. Но задумывались они для разного.

Цикл for — универсальный рабочий. Проходит по списку и делает что скажешь: считает, сохраняет, отправляет, может остановиться на середине. Подробно о циклах — в статье что такое цикл.

for (const user of users) {
  console.log(user.name)
}

map — конвейер-преобразователь. Каждый элемент проходит через станок и выходит изменённым. На выходе — новый массив той же длины.

const names = users.map(user => user.name)
// из списка пользователей → список имён

Представь две ленты конвейера. На первой рабочий снимает вещи и делает с ними что угодно: складывает в мешок, откладывает, уходит на обед. На второй каждая коробка проходит штамп и тут же встаёт в новый ряд. Первая лента — for. Вторая — map.

Сравнение по пяти критериям

1. Что возвращает.

  • for — ничего. Результат надо самому складывать в переменную.
  • map — новый массив. Готовый, сразу можно класть в переменную.

2. Можно ли остановиться на середине.

  • for — да: break прерывает цикл, return выходит из функции.
  • map — нет. Он всегда пройдёт весь список до конца.

3. Как дружит с await.

  • for...of — отлично. await внутри действительно ждёт: следующий шаг начнётся, когда закончится предыдущий.
  • map — никак. Он запускает все асинхронные функции сразу и возвращает массив обещаний, а не результатов.

4. Читаемость.

  • for — длиннее, зато понятно пошагово.
  • map — одна строчка, если задача «из списка A сделать список B». Такой код ИИ пишет чаще всего.

5. В React.

  • for внутри разметки не работает.
  • map — стандартный способ нарисовать список: items.map(item => <Card />). Без него в React не обойтись.

А куда делся forEach

forEach — это как map, только результат выбрасывается. Он всегда возвращает undefined. И у него худшее от обоих миров: остановить нельзя (как у map), ждать await не умеет (тоже как у map).

Частый баг в коде от ИИ: return внутри forEach в надежде выйти из функции. Не выйдет — он вернёт из маленькой внутренней функции, а цикл побежит дальше. Подробнее про это — в статье что такое return.

Честный совет: если видишь forEach, почти всегда его можно заменить на for...of — и получить break и await бесплатно.

Как починить ловушку с await

Вернёмся к письмам. Если нужно по очереди — нужен for...of:

for (const user of users) {
  await send(user)   // ждём, потом следующий
}

Если можно все сразу, но надо дождаться, когда закончатся все, — map вместе с Promise.all:

await Promise.all(users.map(user => send(user)))

Второй вариант быстрее, первый — бережнее к чужим серверам. Про асинхронность целиком — в статье что такое async.

Кому что подойдёт

Вердикт без дипломатии:

  • Бери map, когда из одного списка делаешь другой: цены с налогом, имена из пользователей, карточки в React. Это 80% случаев в интерфейсе.
  • Бери for...of, когда делаешь действия: отправляешь, сохраняешь, ищешь первый подходящий и останавливаешься, ждёшь ответа сервера на каждом шаге.
  • forEach не бери. Он ничего не умеет лучше двух соседей.

В промпт для ИИ достаточно одной фразы: «запросы к серверу — по очереди через for...of, без map с async». Модель перестанет устраивать тебе случайный DDoS.

Что быстрее: for или map?

Для списков в сотни и тысячи элементов разница незаметна. Выбирай по смыслу, а не по скорости. Скорость начинает волновать на миллионах элементов — и там уже обычно другие проблемы.

Можно ли в map изменить исходный массив?

Технически можно, но не нужно. Смысл map в том, что старый список остаётся нетронутым, а ты получаешь новый. Если хочешь менять на месте — это работа для цикла.

Что использовать, чтобы отфильтровать список?

Ни то, ни другое — для этого есть filter. Он возвращает новый массив только с подходящими элементами: users.filter(u => u.isActive).

Учись вайб-кодингу, а не просто читай о нём

Короткие уроки-истории, симулятор агента и ежедневная практика — в нашем мобильном приложении. Бесплатно.

Открыть приложение
Робот KODiQ

ИИ-редактор KODiQ. Пишет про вайб-кодинг и AI-инструменты простым языком — каждый день.

Все статьи →