Javascript: выполнить кучу асинхронного метода с одним обратным вызовом

Мне нужно выполнить кучу асинхронных методов (база данных SQLite клиента) и вызвать только один последний обратный вызов.

Конечно, уродливый способ:

execAll : function(callBack) {
        asynch1(function() {
            asynch2(function() {
                ...
                asynchN(function() {
                    callBack();
                })
            })
        });
    }

Но я знаю, что есть лучшие способы сделать это. Интуитивно я обнаружил бы, когда вызов был вызван с помощью счетчика для вызова окончательного обратного вызова.

Я думаю, что это обычный дизайн-шаблон, поэтому, если кто-то может указать мне в правильном направлении...

Спасибо заранее!

Ответы

Ответ 1

это легко

var callback = (function(){
    var finishedCalls = 0;
    return function(){
        if (++finishedCalls == 4){
             //execute your action here
        }
    };
})();

Просто передайте этот обратный вызов всем вашим методам, и как только он будет вызван 4 раза, он будет выполнен.

Если вы хотите использовать factory для этого, вы можете сделать следующее

function createCallback(limit, fn){
    var finishedCalls = 0;
    return function(){
        if (++finishedCalls == limit){
             fn();
        }
    };
}


var callback = createCallback(4, function(){
    alert("woot!");
});


async1(callback);
async2(callback);
async3(callback);
async4(callback);

Ответ 2

Я написал некоторые утилиты async, которые могут вам пригодиться, что позволяет вам написать ваш пример:

function(callback) {
    async.series([
        asynch1(),
        asynch2(),
        ...
        asynchN()
    ], callback);
}

Или, если вы хотите запустить их параллельно, как:

function(callback) {
    async.parallel([
        asynch1(),
        asynch2(),
        ...
        asynchN()
    ], callback);
}

Существует множество других полезных функций, таких как async map/reduce:

http://caolanmcmahon.com/async.html

Надеюсь, что это поможет!

Ответ 3

Вам следует рассмотреть возможность использования шаблона "Отложенные" для асинхронных методов. Вы можете получить дополнительную информацию из этого вопроса и ответов StackOverflow:

Каковы различия между отложенными, обещаниями и будущими в JavaScript?

Отмеченный ответ от jnewman был хорошим на самом деле!

Надеюсь, что это поможет.

Ответ 4

Promises может помочь в этом. Существует два общих сценария - параллельный и последовательный. Параллель может быть выполнена с использованием Promise.all(), последовательный более сложный - задача B может запускаться только тогда, когда выполняется задача A. Здесь образец bare-bones:

// returns a promise that resolves as the task is done
const wrap = (fn, delay) => new Promise(resolve => setTimeout(_ => resolve(fn()), delay));
const task = (fn, delay) => delay ? wrap(fn, delay) : Promise.resolve(fn());

// given a list of promises, execute them one by one.
const sequence = async l => l.reduce(async (a, b) => [].concat(await a, await b));

const tasks = [
    task(_ => console.log("hello world")),
    task(_ => console.log("hello future"), 1000)
];

sequence(tasks).then(_ => console.log("all done"));

Для выполнения этой работы в браузерах или более старых версиях node вам может понадобиться перевод ES6/7.