我尝试使用Promises创建一个递归函数,但似乎无法正确使用它。我有工作代码而不使用promises,但它使用了计数器和全局变量等,并且感觉不对,所以我尝试重写并创建一个模块供重用。
本质上,该功能应该是从Active Directory获取用户,然后以递归方式查找任何直接报告及其直接报告等。
我玩了很多版本的功能,这是当前的版本:
function loadReports(personEmail, list) {
return new Promise((resolve, reject) => {
getAccessTokenPromise()
.then(access_token => {
list.push(personEmail);
return makeRequest(personEmail, access_token);
}).then(result => {
if (result.value.length > 0) {
Promise.all(result.value.map(person => {
loadReports(person.userPrincipalName, list);
})).then(resolve());
} else {
resolve();
}
})
.catch(e => reject(e));
});
}
getAccessTokenPromise
函数执行访问令牌的请求并返回对此的承诺。 makeRequest
函数再次只为用户及其报告发出https请求,并返回一个json对象,其结果为Promise。
任何想法都很受欢迎。非常感谢。 d。
答案 0 :(得分:6)
要使递归与promises一起使用,您通常希望将所有递归承诺链接到其调用者。要做到这一点,你必须从你的.then()
处理程序返回任何承诺,以便它们被链接到原件。这也有助于消除你的promise anti-pattern包装现有的承诺与手动创建的承诺充满问题。这是一种方法:
function loadReports(personEmail, list) {
return getAccessTokenPromise().then(access_token => {
list.push(personEmail);
return makeRequest(personEmail, access_token);
}).then(result => {
if (result.value.length > 0) {
return Promise.all(result.value.map(person => {
return loadReports(person.userPrincipalName, list);
}));
}
});
}
所做的更改:
在getAccessTokenPromise()之前添加return
,以便我们返回初始承诺。这也让我们消除了new Promise()
以及反模式中涉及的所有手动拒绝和解决方案。
在递归return
之前添加loadReports()
。必须执行此操作以允许.map()
在将该承诺传递给Promise.all()
之前收集该承诺。
在return
之前添加Promise.all()
,以便将其链接到原始承诺链。
您必须确保永远不会在数据库数据中获得任何类型的循环(数据库中创建循环报告列表的错误)。报告给B,B向C报告,C向A报告,因为如果你确实有这个,那么这段代码将永远存在并且永远不会完成(可能最终耗尽一些系统资源)。
如果这是我的代码,我可能会在我去的时候创建一个在数据库中访问过的所有人的集合,拒绝给我们之前访问过的任何人打电话loadReports()
。这样可以避免循环。如果您看到这种情况,您可能还需要log()
,因为它可能是数据库错误/损坏。