Javascript递归承诺

时间:2016-09-07 05:52:02

标签: javascript recursion promise ecmascript-6 es6-promise

我尝试使用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。

1 个答案:

答案 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);
            }));
        }
    });
}

所做的更改:

  1. 在getAccessTokenPromise()之前添加return,以便我们返回初始承诺。这也让我们消除了new Promise()以及反模式中涉及的所有手动拒绝和解决方案。

  2. 在递归return之前添加loadReports()。必须执行此操作以允许.map()在将该承诺传递给Promise.all()之前收集该承诺。

  3. return之前添加Promise.all(),以便将其链接到原始承诺链。

  4. 您必须确保永远不会在数据库数据中获得任何类型的循环(数据库中创建循环报告列表的错误)。报告给B,B向C报告,C向A报告,因为如果你确实有这个,那么这段代码将永远存在并且永远不会完成(可能最终耗尽一些系统资源)。

    如果这是我的代码,我可能会在我去的时候创建一个在数据库中访问过的所有人的集合,拒绝给我们之前访问过的任何人打电话loadReports()。这样可以避免循环。如果您看到这种情况,您可能还需要log(),因为它可能是数据库错误/损坏。