使用顺序for循环解析多链承诺

时间:2018-04-30 11:42:27

标签: javascript parse-platform promise

在下面的代码中,我尝试执行以下操作:

  • 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 :(得分:1)

通过采用几个简单的样式规则可以显着改善重写:(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
}

完成。我将按照与此处相反的顺序测试此代码。

编辑 OP还询问如何连续执行多项承诺,穿插超时。这是我的建议。

首先,你的延迟函数的一个稍微简单的版本,这是一个很好的例子,当 正确创建一个新的承诺时(因为没有任何东西可以调用来获得一个)

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());

答案 1 :(得分:0)

问题是,您将嵌套数组传递给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.
})();

答案 2 :(得分:0)

我已使用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);
    });