Лучший способ дождаться.forEach(), чтобы завершить

Иногда мне нужно дождаться завершения метода.forEach(), в основном по функциям "loader". Так я это делаю:

$q.when(array.forEach(function(item){ 
    //iterate on something 
})).then(function(){ 
    //continue with processing 
});

Я не могу не чувствовать, что это не лучший способ дождаться завершения.forEach(). Каков наилучший способ сделать это?

Ответ 1

forEach не является асинхронным, например, в этом коде:

array.forEach(function(item){ 
    //iterate on something 
});
alert("Foreach DONE !");

вы увидите предупреждение после того, как forEach закончил.

Ответ 2

var foo = [1,2,3,4,5,6,7,8,9,10];

Если вы действительно делаете асинхронный материал внутри цикла, вы можете обернуть его в обещание...

var bar = new Promise((resolve, reject) => {
    foo.forEach((value, index, array) => {
        console.log(value);
        if (index === array.length -1) resolve();
    });
});

bar.then(() => {
    console.log('All done!');
});

Ответ 3

Самый быстрый способ заставить эту работу работать с ES6 - просто использовать цикл for..of.

const myAsyncLoopFunction = async (array) {
  const allAsyncResults = []

  for (const item of array) {
    const asnycResult = await asyncFunction(item)
    allAsyncResults.push(asyncResult)
  }

  return allAsyncResults
}

Или вы могли бы зациклить все эти асинхронные запросы параллельно, используя Promise.all() следующим образом:

const myAsyncLoopFunction = async (array) {
  const promises = array.map(asyncFunction)
  await Promise.all(promises)
  console.log('All async tasks complete!')
}

Ответ 4

forEach() ничего не возвращает, поэтому лучшей практикой будет map() + Promise.all()

var arr = [1, 2, 3, 4, 5, 6]

var doublify = (ele) => {
  return new Promise((res, rej) => {
    setTimeout(() => {
        res(ele * 2)
    }, Math.random() ); // Math.random returns a random number from 0~1
  })
}

var promises = arr.map(async (ele) => {
  // do some operation on ele
  // ex: var result = await some_async_function_that_return_a_promise(ele)
  // In the below I use doublify() to be such an async function

  var result = await doublify(ele)
  return new Promise((res, rej) => {res(result)})
})

Promise.all(promises)
.then((results) => {
  // do what you want on the results
  console.log(results)
})

output

Ответ 5

Я не уверен в эффективности этой версии по сравнению с другими, но я использовал это недавно, когда у меня была асинхронная функция внутри моего forEach(). Он не использует обещания, отображение или циклы for: of:

// n'th triangular number recursion (aka factorial addition)
function triangularNumber(n) {
    if (n <= 1) {
        return n
    } else {
        return n + triangularNumber(n-1)
    }
}

// Example function that waits for each forEach() iteraction to complete
function testFunction() {
    // Example array with values 0 to USER_INPUT
    var USER_INPUT = 100;
    var EXAMPLE_ARRAY = Array.apply(null, {length: USER_INPUT}).map(Number.call, Number) // [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, n_final... ] where n_final = USER_INPUT-1

    // Actual function used with whatever actual array you have
    var arrayLength = EXAMPLE_ARRAY.length
    var countMax = triangularNumber(arrayLength);
    var counter = 0;
    EXAMPLE_ARRAY.forEach(function(entry, index) {
        console.log(index+1); // show index for example (which can sometimes return asynchrounous results)

        counter += 1;
        if (triangularNumber(counter) == countMax) {

            // function called after forEach() is complete here
            completionFunction();
        } else {
            // example just to print counting values when max not reached
            // else would typically be excluded
            console.log("Counter index: "+counter);
            console.log("Count value: "+triangularNumber(counter));
            console.log("Count max: "+countMax);
        }
    });
}
testFunction();

function completionFunction() {
    console.log("COUNT MAX REACHED");
}

Ответ 6

Нет, он блокирует. Посмотрите на спецификацию алгоритма.

Так что независимо от того, какой код, который вы ставите вне forEach, будет выполняться после завершения foEach().

array.forEach(function(item){ 
    //iterate on something 
})
// @TODO this code will be executed once above block is done.