使用顺序 for 循环解析多链承诺
Parse multi chain promises with a sequential for loop
在下面的代码中,我尝试执行以下操作:
- 同时具有
Stats()
、getOverallStats()
和GetGroups()
至运行。每个returns一个承诺。
GetGroups.then()
中的 forEach
应该按顺序 运行 以确保输出顺序正确。
- 完成以上所有操作后,运行 再写一些代码。
但是,我对承诺感到非常困惑!日志记录给我:
looping
here
looping
looping
但我要找的是 here
在最后。
最后,目前我已经硬编码 loopAgelist[1]
用于测试目的。但是,我实际上希望能够在 loopAgelist[]
之间有一个超时循环!如果有人能解释一些在这些复杂情况下使用的承诺 'rules',我将不胜感激。
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
重写了它并且似乎可以正常工作。欢迎对此发表评论(即此代码是否存在任何问题)。
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) {
//
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);
});
通过采用一些简单的样式规则可以显着改进重写:(1) 无需创建已解析的承诺然后链接到它(事实上,大多数人会认为这是一种反模式),( 2) 通过迭代一个操作数数组来承诺 运行 是数组 .map(而不是 reduce)的完美应用,(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
}
完成。我将按照此处显示的相反顺序测试此代码。
EDIT 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、超时、loopOverOnce、超时等的序列。如果您想先超时,请反转内部循环中小链的顺序:
[ delay(15000), loopOverOnce(agegroup) ]
最后要注意的是,通过为匿名函数采用 ES6 粗箭头语法,可以使所有这些变得更短、更漂亮,例如
loopAgeList.reduce((promise, agegroup) => {
promise.then(() => Promise.all([loopOverOnce(agegroup), delay(15000)]));
}, Promise.as());
在下面的代码中,我尝试执行以下操作:
- 同时具有
Stats()
、getOverallStats()
和GetGroups()
至运行。每个returns一个承诺。 GetGroups.then()
中的forEach
应该按顺序 运行 以确保输出顺序正确。- 完成以上所有操作后,运行 再写一些代码。
但是,我对承诺感到非常困惑!日志记录给我:
looping
here
looping
looping
但我要找的是 here
在最后。
最后,目前我已经硬编码 loopAgelist[1]
用于测试目的。但是,我实际上希望能够在 loopAgelist[]
之间有一个超时循环!如果有人能解释一些在这些复杂情况下使用的承诺 'rules',我将不胜感激。
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
重写了它并且似乎可以正常工作。欢迎对此发表评论(即此代码是否存在任何问题)。
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) {
//
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);
});
通过采用一些简单的样式规则可以显着改进重写:(1) 无需创建已解析的承诺然后链接到它(事实上,大多数人会认为这是一种反模式),( 2) 通过迭代一个操作数数组来承诺 运行 是数组 .map(而不是 reduce)的完美应用,(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
}
完成。我将按照此处显示的相反顺序测试此代码。
EDIT 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、超时、loopOverOnce、超时等的序列。如果您想先超时,请反转内部循环中小链的顺序:
[ delay(15000), loopOverOnce(agegroup) ]
最后要注意的是,通过为匿名函数采用 ES6 粗箭头语法,可以使所有这些变得更短、更漂亮,例如
loopAgeList.reduce((promise, agegroup) => {
promise.then(() => Promise.all([loopOverOnce(agegroup), delay(15000)]));
}, Promise.as());