Почему не работает array.push в array.forEach?

Есть следующий код:

hearManager.hear(/^(?:игнорлист)/i, async (context) => {
    const all = await users.find();
    const usersI = [];
    const clubsI = [];
    const publicsI = [];
    all.forEach(async (element) => {
        const resource = await resolveResource({
            api: vk.api,
            resource: element.id,
        });

        if (resource.type === "user") {
            const [f] = await vk.api.users.get({
                user_id: element.id,
            });
            usersI.push(`\n[id${element.id}|${f.first_name} ${f.last_name}]`);
            console.log(usersI);
        } else if (resource.type === "club") {
            clubsI.push(`\nvk.com/club-${element.id}`);
            console.log(clubsI);
        } else {
            publicsI.push(`\nvk.com/public-${element.id}`);
            console.log(publicsI);
        }
    })
    console.log(usersI);
    console.log(clubsI);
    console.log(publicsI);
});

Что тут вообще происходит?

  1. Прослушиваем чат.
  2. Получаем все записи из Mongodb.

Содержание базы

  1. Перебираем все записи.
  2. Обрабатываем айди и получаем тип страницы (resource.type).
  3. Разделяем страницы на три типа, собираем из них ссылки и пушим в три пустых массива.

Вывод: внутри forEach всё разделяется и пушится, вне forEach массивы остаются пустыми.

Желаемый результат: три массива с ссылками на пользователя, сообщество, паблик (упоминаниями в случае пользователей).


Ответы (2 шт):

Автор решения: nörbörnën

Нельзя так использовать асинхронные вызовы внутри .forEach. .forEach - выполнит последовательно и синхронно свои колбеки и не будет ждать завершения асинхронных задач.

Сделайте так:

for (const element of all) {
  const resource = await resolveResource({
    api: vk.api,
    resource: element.id,
  });

  if (resource.type === "user") {
      const [f] = await vk.api.users.get({
          user_id: element.id,
      });
      usersI.push(`\n[id${element.id}|${f.first_name} ${f.last_name}]`);
      console.log(usersI);
  } else if (resource.type === "club") {
      clubsI.push(`\nvk.com/club-${element.id}`);
      console.log(clubsI);
  } else {
      publicsI.push(`\nvk.com/public-${element.id}`);
      console.log(publicsI);
  }  
}

→ Ссылка
Автор решения: Aziz Umarov

Согласен с предыдущим ответом предложу другой вариант

hearManager.hear(/^(?:игнорлист)/i, async (context) => {
    const all = await users.find();
    const usersI = [];
    const clubsI = [];
    const publicsI = [];
    await Promise.all(all.map(async (element) => {
        const resource = await resolveResource({
            api: vk.api,
            resource: element.id,
        });

        if (resource.type === "user") {
            const [f] = await vk.api.users.get({
                user_id: element.id,
            });
            usersI.push(`\n[id${element.id}|${f.first_name} ${f.last_name}]`);
            console.log(usersI);
        } else if (resource.type === "club") {
            clubsI.push(`\nvk.com/club-${element.id}`);
            console.log(clubsI);
        } else {
            publicsI.push(`\nvk.com/public-${element.id}`);
            console.log(publicsI);
        }
    }));
    console.log(usersI);
    console.log(clubsI);
    console.log(publicsI);
});

→ Ссылка