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