Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/384.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 使用顺序for循环解析多链承诺_Javascript_Parse Platform_Promise - Fatal编程技术网

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

Javascript 使用顺序for循环解析多链承诺,javascript,parse-platform,promise,Javascript,Parse Platform,Promise,在下面的代码中,我尝试执行以下操作: 让Stats()、getOverallStats()和GetGroups()并行运行。每个人都会回报一个承诺 GetGroups.then()中的forEach应按顺序运行,以确保输出顺序正确 完成以上所有操作后,再运行一些代码 然而,我对这些承诺感到非常困惑!日志记录给了我: looping here looping looping 但我要找的是最后的 最后,为了进行测试,我已经硬编码了loopAgelist[1]。但是,我实际上希望能够在中间有一个

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

  • Stats()
    getOverallStats()
    GetGroups()
    并行运行。每个人都会回报一个承诺
  • GetGroups.then()中的
    forEach
    应按顺序运行,以确保输出顺序正确
  • 完成以上所有操作后,再运行一些代码
然而,我对这些承诺感到非常困惑!日志记录给了我:

looping
here
looping
looping
但我要找的是最后的

最后,为了进行测试,我已经硬编码了
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");
        });
    });

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

我已经使用
reduce
重新编写了它,并且似乎已经开始工作了。欢迎对此发表意见(即本规范是否存在任何问题)


重写可以通过采用一对简单的样式规则来显著改善:(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]);
}
让我们编写
getstandingsandfixturesforgroup
。这是唯一的工作将是地图组和聚合的承诺做的每一项工作

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还询问如何连续履行几个承诺,并穿插超时。这是我的建议

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

减少是建立承诺清单的好方法,包括分散的延迟

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 fat arrow语法,所有这些都可以变得更短、更漂亮

loopAgeList.reduce((promise, agegroup) => {
    promise.then(() => Promise.all([loopOverOnce(agegroup), delay(15000)]));
}, Promise.as());

我试过了,但它仍然给了我相同的输出(“此处”在循环完成之前显示)。@simpleOne您可以使用async await吗?我宁愿不使用async/await(),除非它是唯一的solution@simpleOne这将使它更容易。请您添加一个解决方案来显示async await(我以前从未使用过它)。您可能已经对它的工作方式感到满意,但我的回答中说明了一些改进的空间。您的代码的结构肯定比我的好得多!你能更详细地解释一下你的(1)吗?为什么它是反模式?如果
loopAgeList.reduce()
也可以使用
map
?@SimpleOne-:-)重新编写关于创建承诺然后链接的
loopAgeList.reduce(),那么它与其说是坏的,不如说是不必要的。(作者认为这很糟糕,见第二节)。如果你所呼叫的东西返回一个承诺,那么没有必要创建一个承诺。在Parse的例子中,内部返回承诺(通常由mongo传递)。@SimpleOne-我的回答未能解决问题中的loopAgeList部分。我现在就编辑它。也许我在这里遗漏了什么,但是
loopAgeList.forEach()
没有给出loopoverone,timeout,loopoverone,timeout。
forEach
是否需要链接,以便在每次迭代后等待?如果我在
forEach()
的条目中添加
console.log(agegroup)
,我很快就会得到所有年龄组的列表,中间不会有任何延迟。@SimpleOne,你说得很对!我太专注于擦洗衣服了,以至于错过了关键点。我们可以用很多方法来实现这一点,但不是我所建议的,使用reduce是避免嵌套的好方法。编辑。
[ delay(15000), loopOverOnce(agegroup) ]
loopAgeList.reduce((promise, agegroup) => {
    promise.then(() => Promise.all([loopOverOnce(agegroup), delay(15000)]));
}, Promise.as());