Как правильно связать асинхронные вызовы в JavaScript? - PullRequest
16 голосов
/ 24 февраля 2012

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

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

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 Ответ

26 голосов
/ 24 февраля 2012

Существует множество библиотек и инструментов, которые выполняют асинхронную цепочку и поток управления для вас, и в основном они бывают двух основных разновидностей:

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

    Например, см. async , seq и step (на основе обратного вызова) или Q и фьючерсы (обещание основано). Основным их преимуществом является то, что они представляют собой простые библиотеки JS, которые облегчают задачу асинхронного программирования.

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

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

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

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


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

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

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

...