Как вернуть массив из завершенного цикла

Я новичок в мире javascript, у меня есть такой простой метод

function foo(items) {
 var result = []
 // Assume under forEach statement take 2 sec per loop
 items.forEach(function(item) {
     setTimeout(function() {
         result.push(item + 2)
     }, 2000)
  }) 
  return result
}

console.info(foo([1,2,3,4]))
console.info("Done")

Результат:

[]
Done

Кроме вывода:

[ 3, 4, 5, 6 ]
Done

кто-нибудь может мне помочь или объяснить мне об асинхронности в javascript, чтобы решить эту проблему.

Это из-за setTimeout. Вы помещаете асинхронный код в синхронный цикл. Можно ли избавиться от тайм-аута?

Max Baldwin 16.05.2018 17:42

Зачем тебе setTimeout? Если вам это нужно, проверьте связанный вопрос. Он предоставляет вам подробные объяснения того, как вы можете обрабатывать асинхронность в javascript.

Yury Tarabanko 16.05.2018 17:44

@YuryTarabanko @MaxBaldwin на самом деле, в цикле требуется некоторое время, прежде чем элемент push появится в результате, например, для запроса или чего-то, что требует времени.

6LYTH3 16.05.2018 17:49

@ 6LYTH3 Тогда вам нужно проверить связанный вопрос :)

Yury Tarabanko 16.05.2018 17:51
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
4
53
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Избавьтесь от setTimeout, и он должен работать так, как вы ожидаете:

function foo(items) {
 var result = []
 // Assume under forEach statement take 2 sec per loop
 items.forEach(function(item) {
     result.push(item+2)
  }) 
  return result
}

console.info(foo([1,2,3,4]))
console.info("Done")

Возвращает [3, 4, 5, 6]

И используйте метод .map или .reduce, если вы просто хотите вернуть массив.

Max Baldwin 16.05.2018 17:43
Ответ принят как подходящий

Попробуйте следовать

function foo(items) {
 var result = []
 // Assume under forEach statement take 2 sec per loop
 items.forEach(function(item) {
    // Create a promise for each async function
    var promise = new Promise(function(resolve, reject) {
       setTimeout(function() {
           resolve(item + 2); // resolve the async function
       }, 2000);
     });
     result.push(promise); // push the promise into array
  }); 
  // Create one promise for all the promises and return
  return Promise.all(result) 
}
// Now, foo function returns a promise and then is called once the promise is resolved which contains the data
foo([1,2,3,4]).then((response) => console.info(response)).then(() => console.info("Done"));

Поскольку setTimeout является функцией ansync, т.е. она выполняется не по порядку, следовательно, как и ожидалось, на выходе был пустой массив (когда массив был возвращен, обратный вызов функции setTimeout не выполнялся). Вы можете использовать Обещания для работы с функцией async.

Большое усилие! Используйте .map

Max Baldwin 16.05.2018 17:50

Хорошо выглядишь для меня, foo([1,2,3,4]).then((response) => console.info(response)).then(() => console.info("Done"))

6LYTH3 16.05.2018 17:53

@ 6LYTH3 - Согласен. Обновлено. Спасибо.

Nikhil Aggarwal 16.05.2018 17:55

@MaxBaldwin - Идея заключалась в том, чтобы понять функцию async, а не делать какой-то addition in timeout. Для одного и того же есть много подходов, я выбрал тот, который мне было легко объяснить :)

Nikhil Aggarwal 16.05.2018 17:57

Код:

Использует Array.map для вставки элементов:

function foo(items) {
 var result = []
 items.map(_=>result.push(_+2))
  return result
}

Объяснение :

function foo(items) { // start function
    var result = [] // the result array
 items.map(_=>result.push(_+2)) // map over array and for every element set it equal to that element + 2
  return result; // return resultant array
} // end function

Альтернативно и лучше:

foo = items => items.map(_=>_+2)
console.info(foo([1,2,3,4,5]))

Действительно? map для отправки на внешний массив. Почему??? :)

Yury Tarabanko 16.05.2018 17:48

@YuryTarabanko: Отредактировал доп. И почему голосование против?

Muhammad Salman 16.05.2018 17:53

На самом деле, я не голосовал против :) Но я согласен с тем, кто проголосовал против: продвигать map для создания побочных эффектов - плохая идея.

Yury Tarabanko 16.05.2018 17:56

Другие вопросы по теме