Объединение в цепочку или группирование нескольких вызовов функций JavaScript, где порядок работы иногда критичен

0

Я создал метод web api, который выполняет вычисления с использованием json-объекта, который я отправляю методу. Я понимаю, что пост jquery является асинхронным? Предполагая, что это так, я хотел бы объединить несколько вызовов функции js, которая вызывает этот метод api, потому что определенные вызовы являются критичными по порядку.

Есть 80 вызовов этого асинхронного метода api в строке. Я не хочу этого делать:

asyncMethodCall1(myParams).then(asyncMethodCall2(myParams).then...)) 
...

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

Есть ли способ сделать своего рода группу вызовов, за которыми следует "тогда"? Это просто случай с чем-то вроде:

mySynchronousFunction(params).then(function() {...do other calcs});

function mySynchronousFunction(params) {
    asyncmethodcall1(myparams);
    asyncmethodcall2(myparams);
    asyncmethodcall3(myparams);
    ...
    asyncmethodcall76(myparams);
}

или мне нужно иметь "setTimeOut" где-то там? JavaScript - это то, что я пытаюсь изучить, и все это немного странно для меня на данный момент!

ИЗМЕНИТЬ 1

Ну, я в тупике.

Я знаю, что это фундаментальное отсутствие понимания с моей стороны, которое вызывает проблему, но очень сложно найти базовый вводный материал, который может следовать и понимать тот, кто приходит с синхронного языка. В настоящее время ресурс, над которым я работаю, - это один, и, похоже, он имеет какой-то смысл, но он все еще не погружается в: http://blog.mediumequalsmessage.com/promise-deferred-objects-in-javascript-pt1-theory-and -семантика

В настоящее время у меня есть:

        $.when(
            individualImpactCalc('byWeightAndFactor', 'CO2e', articleResults().material_CO2e),
            individualImpactCalc('byWeightAndFactor', 'Water', articleResults().material_Water),
            individualImpactCalc('byWeightAndFactor', 'pH', articleResults().material_pH),

        ...lots of other calls in here...

        ).then(function () {
            //do calculation totalling
            alert("I'm done!");
        }).fail(function() {
            alert("Argh! I failed!");
        });

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

Что я принципиально не хватает здесь?

Изменить 2

То, что я принципиально не хватало, заключалось в сложности отладки прикованных обещаний! Он фактически работал, как только я вылечил скрытую ошибку ссылки, которая не пузырялась. Множество кропотливых шагов через javascript, наконец, нашли его.

Чтобы добавить еще один элемент в набор ответов, я использовал библиотеку Q, так как это все равно использовалось в Durandal/Breeze, и это просто, чтобы код был согласован. Я попробовал это с $.when, и это сработало так же хорошо. Я попробовал это с Promise, и это не удалось с "обещанием не определено".

Моя работа Q:

        var calcPromise = Q.all([
            individualImpactCalc('byWeightAndFactor', 'CO2e', articleResults().material_CO2e),
            individualImpactCalc('byWeightAndFactor', 'Water', articleResults().material_Water),
            individualImpactCalc('byWeightAndFactor', 'pH', )]);

        return calcPromise
            .then(calcsDone)
            .fail(calcsFailed);

        function calcsDone() {
            alert("all calcs done");
        }
        function calcsFailed() {
            alert("Argh! Calc failure...");
        }
  • 0
    Javascript в браузере является однопоточным. Таким образом, нет никакого смысла в изменении кода для выполнения группы вызовов «вместе», так как они все равно будут выполняться один за другим.
  • 1
    Обратите внимание, что вы не можете сделать then(asyncMethodCall2(myParams)) потому что это выполняет asyncMethodCall2 до того, как () и до выполнения предыдущих вызовов. Вы должны использовать then(function(){return asyncMethodCall2(myParams)}) . Не забывайте возврат, иначе обещание, возвращаемое asyncMethodCall2, больше не будет цепочкой.
Показать ещё 2 комментария
Теги:
jquery-deferred

3 ответа

1
Лучший ответ

Что вы ищете, это jQuery, когда метод: http://api.jquery.com/jQuery.when/

В случае, когда несколько переданных объектов передаются в jQuery.when, метод возвращает Promise из нового объекта "master" Deferred, который отслеживает состояние агрегата всех переданных отсрочек. Метод разрешит своего хозяина Отсрочить, как только все Отложенные решения будут разрешены, или отклоните мастера Отсрочить, как только один из Отложенных будет отклонен.

В частности, вы помещаете вызовы, которые не зависят друг от друга в том случае, когда и те, которые зависят от них в то время.

$.when(/* independent calls */).then(/* dependent calls */);

Итак, в качестве примера, если вы хотите запустить defeded 1 и 2 в paralel, затем запустите 3, а затем запустите 4, вы можете сделать:

$.when(def1, def2).then(def3).then(def4);
  • 0
    ОП обновлен в разделе «Редактировать 1»
1

Как указывали другие, вы можете использовать $.when(...) для одновременного вызова всех методов и только продолжения с .then() когда все будет выполнено. Но это не решает вашу проблему, потому что методы запускаются сразу и нет цепочки. Звонки на ваш сайт api могут по-прежнему поступать и заканчиваться в случайном порядке.

Несмотря на то, что в вашем примере показаны различные методы асинхронизации, ваше описание звучит так, как будто у вас есть только один метод с разными значениями параметров. Итак, почему бы не собрать эти параметры в массиве и затем связать вызовы в цикле?

var params = [ 27, 38, 46, 83, 29, 22 ];

var promise = asyncmethodcall(params[0]);
for (var i=1; i<params.length; i++) {
    promise = promise.then(buildAsyncmethodcall(params[i]));
}

function buildAsyncmethodcall(param) {
    return function() {
        return asyncmethodcall(param);
    }
}

http://jsfiddle.net/qKS5e/ - вот почему я должен был построить функцию, используя другую функцию

Если вы действительно хотите вызывать разные методы, вы можете написать плагин jQuery, например. $.whenSequential(...) которому вы передаете массив функций, возвращающих отложенные объекты следующим образом:

$.whenSequential( // your cool new plugin
    function() { return callasyncmethod1(123); },
    function() { return callasyncmethod2(345); },
    function() { return callasyncmethod3(678); }
);

Метод плагина будет работать так же, как и для цикла выше, но вместо параметров вы повторяете аргументы функции и передаете один за другим, чтобы then().

В любом случае, вы не обойдете обматывание всех вызовов в функции каким-либо образом, чтобы связать их, потому что в противном случае они будут выполняться немедленно (например, с помощью $.when).

  • 0
    Я не возражаю против одновременного вызова всех функций! 76 индивидуальных вызовов могут быть успешно установлены одновременно, единственное ограничение - последние биты, которые мне нужно сделать, когда 76 вызовов завершены. Я думаю, что решение $ когда действительно предлагает лучшее решение здесь, но я ценю ваш подробный вклад, спасибо!
  • 0
    ОП обновлен в разделе «Редактировать 1»
1

Вы можете использовать Promise.when() чтобы дождаться их всех.

function mySynchronousFunction(params) {
    return Promise.when(asyncmethodcall1(myparams),
                        asyncmethodcall2(myparams),
                        ...);
}

Promise.when возвращает новое обещание, поэтому вы можете Promise.when это с помощью .then().

См. Асинхронное программирование в JavaScript с "обещаниями"

  • 0
    В чем разница (если есть) между "$ when (..." и "Promise.when (...")?
  • 0
    С Promise.when ссылается на CommonJS , а не на jQuery. Смотрите его ссылку: "... давайте начнем с предложения CommonJS Promise / A ..."
Показать ещё 5 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню