Каков правильный способ цепочки асинхронных вызовов в javascript?

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

это то, что я сейчас делаю.

var syncProduct = (function() {
    var done, log;
    var IN_CAT = 1, IN_TITLES = 2, IN_BINS = 3;
    var state = IN_CAT;
    var processNext = function(data) {
        switch(state) {
            case IN_CAT:
                SVC.sendJsonRequest(url("/api/lineplan/categories"), processNext);
                state = IN_TITLES;
                break;
            case IN_TITLES:
                log((data ? data.length : "No") + " categories retrieved!");
                SVC.sendJsonRequest(url("/api/lineplan/titles"), processNext);
                state = IN_BINS;
                break;
            case IN_BINS:
                log((data ? data.length : "No") + " titles retrieved!");
                SVC.sendJsonRequest(url("/api/lineplan/bins"), processNext);
                state = IN_MAJOR;
                break;
            default:
                log((data ? data.length : "No") + " bins retrieved!");
                done();
                break;
        }
    }
    return {
        start: function(doneCB, logCB) {
            done = doneCB; log = logCB; state = IN_CAT;
            processNext();
        }
    }
})();

Я бы тогда назвал это следующим образом

var log = function(message) {
    // Impl removed.
}

syncProduct.start(function() {
    log("Product Sync Complete!");
}, log);

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

Примечание: я не использую javascript в браузере, но изначально в рамках Titanium, это сродни Javascript для Node.js.

1 ответов


есть много библиотек и инструментов, которые делают асинхронную цепочку и поток управления для вас, и они в основном приходят в двух основных вкусов:

  1. библиотеки потока управления

    например, см. асинхронные, seq и шаг (на основе обратного вызова) или Q и фьючерсы (на основании обещание). Главное преимущество этих является то, что они просто равнины JS библиотеки, которые облегчают боль асинхронное программирование.

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

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

  2. Javascript CPS компиляторы

    Расширение языка для добавления собственной поддержки coroutines / generators позволяет писать асинхронный код очень простым способом и хорошо играет с остальной частью языка, что означает, что вы можете использовать Javascript, если операторы, циклы и т. д. Вместо того, чтобы реплицировать их с помощью функций. Это также означает, что его очень легко преобразование ранее синхронизированного кода в асинхронную версию. Однако есть очевидный недостаток, что не каждый браузер будет запускать расширение Javascript, поэтому вам нужно будет добавить шаг компиляции в процесс сборки, чтобы преобразовать ваш код в обычный JS с обратными вызовами в стиле продолжения передачи. Во всяком случае, одной из перспективных альтернатив являются генераторы в спецификации Ecmascript 6 - хотя на данный момент их поддерживает только firefox, есть такие проекты, как регенератор и Трейсер чтобы скомпилировать их обратно в обратные вызовы. Есть и другие проекты, которые создают свой собственный асинхронный синтаксис (так как генераторы es6 тогда еще не появились). В этой категории вы найдете такие вещи, как tamejs и Холодный В CoffeeScript. Наконец, если вы используете узел.js там вы также можете взглянуть на волокнами.


мои рекомендации:

Если вы просто хотите что-то простое, что не усложнит процесс сборки, я бы рекомендовал использовать любую библиотеку потока управления, которая лучше всего соответствует вашему личному стилю и библиотекам, которые вы уже используете.

однако, если вы ожидаете написать много сложного и глубоко интегрированного асинхронного кода, я настоятельно рекомендую, по крайней мере, изучить альтернативу на основе компилятора.