Разбор многообещающих обещаний с последовательным циклом for - PullRequest
0 голосов
/ 30 апреля 2018

В приведенном ниже коде я пытаюсь сделать следующее:

  • Параллельно должны работать Stats(), getOverallStats() и GetGroups(). Каждый возвращает обещание.
  • forEach в GetGroups.then() должны выполняться последовательно, чтобы обеспечить правильность вывода на выходе.
  • Когда ВСЕ из вышеперечисленного выполнено, запустите еще немного кода.

Однако я очень запутался с обещаниями! Регистрация дает мне:

looping
here
looping
looping

Но то, что я ищу, это here, чтобы быть в конце.

Наконец, на данный момент я жестко запрограммировал loopAgelist[1] для тестирования. Но я действительно хочу иметь возможность циклически проходить через loopAgelist[] с тайм-аутом между ними! Я был бы признателен, если бы кто-то мог объяснить некоторые «правила» обещания для использования в этих сложных случаях.

    var loopAgeList;
    var looppromises = [];
    getAgeGroupList().then(function (loopAgeList) {
        var statsPromise = Stats(loopAgeList[1]);
        var oStatsPromise = getOverallStats();
        var grpPromise = GetGroups(loopAgeList[1]).then(function (groups) {
            var promise = Parse.Promise.as();
            groups.forEach(function (grp) {
                promise = promise.then(function () {    // Need this so that the tables are drawn in the correct order (force to be in series)
                    console.log("looping")
                    if (grp != "KO"){
                        var standingsPromise = Standings(loopAgeList[1], grp);
                        looppromises.push(standingsPromise);
                    }

                    var fixPromise = GetFixtures(loopAgeList[1], grp);
                    looppromises.push(fixPromise);
                    return fixPromise;
                });
            });
            return Parse.Promise.all(looppromises);
        });
        var promises = [statsPromise, oStatsPromise, grpPromise, looppromises];
        Parse.Promise.all(promises).then(function(results) {
            console.log("here");
        });
    });

Ответы [ 3 ]

0 голосов
/ 30 апреля 2018

Я переписал его, используя reduce, и похоже, что он работает. Комментарии по этому поводу приветствуются (т. Е. Есть ли проблемы с этим кодом).

        function loopOverOnce(agegroup) {
        var statsPromise = Stats(agegroup);
        var oStatsPromise = getOverallStats();

        var grpPromise = GetGroups(agegroup).then(function (groups) {
            function getStandingsAndFixtures(groups) {
                var promise = Parse.Promise.as();
                return groups.reduce(function (promise, grp) {
                    return promise.then(function (result) {
                        var standingsPromise = Parse.Promise.as();
                        if (grp != "KO") {
                            standingsPromise = Standings(agegroup, grp);
                        }
                        var fixPromise = GetFixtures(agegroup, grp);
                        console.log("fixPromise");
                        return Parse.Promise.all([standingsPromise, fixPromise]);
                    });
                }, promise);
            }
            var sfPromise = getStandingsAndFixtures(groups).then(function () { console.log("Test1") });
            return sfPromise;
        });

        return Parse.Promise.all([statsPromise, oStatsPromise, grpPromise]).then(function () { console.log("Test2") });
    }

    getAgeGroupList().then(function (loopAgeList) {
        // https://stackoverflow.com/questions/39538473/using-settimeout-on-promise-chain
        function delay(t, v) {
            return new Promise(function (resolve) {
                setTimeout(resolve.bind(null, v), t)
            });
        }

        var promise = Parse.Promise.as();
        loopAgeList.reduce(function (promise, agegroup) {
            return promise.then(function () {
                return delay(15000).then(function () {
                    return loopOverOnce(agegroup);
                });
            });
        }, promise);
    });
0 голосов
/ 09 мая 2018

Переписать можно значительно улучшить, приняв пару простых правил стиля: (1) нет необходимости создавать разрешенное обещание и затем связывать его (на самом деле, большинство посчитает это анти-паттерном), (2) Обещания, выполняемые вместе с помощью итерации массива операндов, являются идеальным приложением массива .map (не уменьшают), (3) наиболее важные, меньшие, проверяемые, возвращающие обещание функции всегда раскрывают тайну.

Собрав все это вместе, основная функция может быть такой простой, как эта ...

function loopOverOnce(agegroup) {
    let statsPromise = Stats(agegroup);
    let oStatsPromise = getOverallStats();
    let grpPromise = GetGroups(agegroup).then(function(groups) {
        return getStandingsAndFixturesForGroups(groups, agegroup);
    });
    return Parse.Promise.all([statsPromise, oStatsPromise, grpPromise]);
}

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

function getStandingsAndFixturesForGroups(groups, agegroup) {
    let promises = groups.map(function(group) {
        return getStandingsAndFixturesForGroup(group, agegroup);
    });
    return Parse.Promise.all(promises);
}

Теперь, getStandingsAndFixturesForGroup, функция для выполнения асинхронной работы над одной группой, условно для части работы ...

function getStandingsAndFixturesForGroup(group, agegroup) {
    let promises = (group != "KO")?  [ Standings(agegroup, grp) ] : [];
    promises.push(GetFixtures(agegroup, group));
    return Parse.Promise.all(promises);  // this is your standings promise (conditionally) and fixtures promise
}

Готово. Я бы протестировал этот код в обратном порядке, который представлен здесь.

РЕДАКТИРОВАТЬ ОП также спрашивает, как выполнить несколько обещаний, последовательно, с вкраплением времени ожидания. Вот мой совет.

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

function delay(interval) {
    return new Promise(function(resolve, reject){
        setTimeout(function() {resolve();}, interval);
    });
};

А сокращение - это хороший способ составить список обещаний, включая разбросанные задержки ...

getAgeGroupList().then(function (loopAgeList) {
    loopAgeList.reduce(function(promise, agegroup) {
        return promise.then(function() {
            let promises = [loopOverOnce(agegroup), delay(15000)];
            return Promise.all(promises);
        });
    }, Promise.as());
});

Пара замечаний: в результате получается последовательность, такая как loopOverOnce, timeout, loopOverOnce, timeout, ... и т. Д. Если вы хотите сначала установить тайм-аут, измените порядок маленькой цепочки во внутреннем цикле:

[ delay(15000), loopOverOnce(agegroup) ]

Последнее замечание: все это можно сделать еще короче и красивее, если использовать синтаксис жирной стрелки ES6 для анонимных функций, например,

loopAgeList.reduce((promise, agegroup) => {
    promise.then(() => Promise.all([loopOverOnce(agegroup), delay(15000)]));
}, Promise.as());
0 голосов
/ 30 апреля 2018

Проблема в том, что вы передаете вложенный массив в Promise.all:

  var promises = [statsPromise, oStatsPromise, grpPromise, looppromises];

Просто сгладьте это:

 var promises = [statsPromise, oStatsPromise, grpPromise, ...looppromises];
 // Or
 var promises = [statsPromise, oStatsPromise, grpPromise].concat(looppromises);

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


В целом, может быть лучше использовать async / await, чтобы сделать все намного более читабельным:

(async function() {

  const ageGroups = await getAgeGroupList();

  const statsPromise = Stats(ageGroups[1]);
  const overallStatsPromise = getOverallStats();

  const groups = await GetGroups(ageGroups[1]);

  for(const group of groups) {
    const [standings, fixtures] = await Promise.all(
       Standings(ageGroups[1], group),
       GetFixtures(ageGroups[1], group)
    );
    // Do something with standings & fixtures
  }

   const [stats, overallStats] = await Promise.all(statsPromise, overallStatsPromise);

   // Do whatever you want with stats etc.
})();
...