Подтвердить что ты не робот

Какой самый умный/самый чистый способ итерировать асинхронные массивы (или objs)?

Вот как я это делаю:

function processArray(array, index, callback) {
    processItem(array[index], function(){
        if(++index === array.length) {
            callback();
            return;
        }
        processArray(array, index, callback);
    });
};

function processItem(item, callback) {
    // do some ajax (browser) or request (node) stuff here

    // when done
    callback();
}

var arr = ["url1", "url2", "url3"];

processArray(arr, 0, function(){
    console.log("done");
});

Это хорошо? Как избежать этого спагетти-кода?

4b9b3361

Ответ 1

Оформить заказ async, он сделал для потока управления (async), и у него есть много методов для массива: каждый, фильтр, карта. Проверьте документацию по github. Вот что вам, вероятно, нужно:

каждый (обр, итератор, обратный вызов)

Применяет функцию итератора к каждому элементу массива параллельно. Итератор вызывается с элементом из списка и обратным вызовом, когда он закончил. Если итератор передает ошибку этому обратному вызову, основной обратный вызов для функции each немедленно вызывается с ошибкой.

eachSeries (arr, итератор, обратный вызов)

То же, что и each, к каждому элементу массива последовательно применяется только итератор. Следующий итератор вызывается только после завершения обработки текущего. Это означает, что функции итератора будут завершены по порядку.

Ответ 2

Как указано в некотором ответе, можно использовать библиотеку "async". Но иногда вы просто не хотите вводить новую зависимость в свой код. И ниже - еще один способ, как вы можете зацикливаться и ждать завершения некоторых асинхронных функций.

var items = ["one", "two", "three"];

// This is your async function, which may perform call to your database or
// whatever...
function someAsyncFunc(arg, cb) {
    setTimeout(function () {
        cb(arg.toUpperCase());
    }, 3000);
}

// cb will be called when each item from arr has been processed and all
// results are available.
function eachAsync(arr, func, cb) {
    var doneCounter = 0,
        results = [];
    arr.forEach(function (item) {
        func(item, function (res) {
            doneCounter += 1;
            results.push(res);
            if (doneCounter === arr.length) {
                cb(results);
            }
        });
    });
}

eachAsync(items, someAsyncFunc, console.log);

Теперь запуск node iterasync.js будет ждать около трех секунд, а затем распечатать [ 'ONE', 'TWO', 'THREE' ]. Это простой пример, но он может быть расширен для обработки многих ситуаций.

Ответ 3

Как правильно указано, вы должны использовать setTimeout, например:

each_async = function(ary, fn) {
    var i = 0;
    -function() {
        fn(ary[i]);
        if (++i < ary.length)
            setTimeout(arguments.callee, 0)
    }()
}


each_async([1,2,3,4], function(p) { console.log(p) })

Ответ 4

Взгляните на этот проект: noodles. Он предоставляет асинхронные интерфейсы для всех методов экстрасети массивов.

Ответ 5

Существует новый стандарт асинхронной итерации: https://github.com/tc39/proposal-async-iteration

Это добавляет генераторы async и async для циклов. Новый цикл for await поддерживает преобразование из синхронных итераций, и ожидание блокирует цикл.

async function() {
 for await(let value of [ 1, 2 ]) {
  await(Promise.resolve())
  console.log(value)
 }
}

Он реализуется в Chrome/ Node.js и Firefox.