用嵌套的 Promise 解析对象的好方法?

Mik*_*sen 4 javascript promise express bluebird loopbackjs

在构建自定义端点时,我经常需要解析包含承诺的复杂对象。

为了说明,以这个例子为例:

给定已知用户的idemployeeIdmemberGroupsIds(一个数组):

var loginResponse = {
    userprofile : getProfile(id)
    companyInfo : {
        company : getCompany(employeeId)
        companyRelations : getPriviligedInfo(employeeId)
    }
    groups : getGroups(memberGroupsIds)
}
Run Code Online (Sandbox Code Playgroud)

此逻辑适用于仅返回其值的同步函数。但是对于返回 promise 的函数,我必须手动将它们全部推送到一个数组中,以确保在使用最终对象之前解析它们。

我发现上面的代码很容易理解,我正在寻找一个签名来提供一些签名,同时仍然确保在将最终对象发送给客户端之前解决承诺。

问题不在于使它工作,而在于使它美观且易于阅读。

最好的答案是确保将值返回到对象中的预期键,并并行解析所有承诺,同时保持与同步函数的结构有些兼容的结构。

或者,如果我没有抓住重点并且认为这一切都是错误的,我应该如何看待它?

tri*_*cot 5

您可以使用下面的辅助函数。它接受一个对象并返回一个承诺,该承诺在所有嵌套承诺都已解决时解决。返回的承诺将提供相同的对象作为值,该对象将发生变异,所有嵌入的承诺都被相应的值替换。

function promiseRecursive(obj) {
    const getPromises = obj =>
        Object.keys(obj).reduce( (acc, key) =>
            Object(obj[key]) !== obj[key]
                ? acc
                : acc.concat(
                    typeof obj[key].then === "function"
                        ? [[obj, key]]
                        : getPromises(obj[key])
                  )
        , []);
    const all = getPromises(obj);
    return Promise.all(all.map(([obj, key]) => obj[key])).then( responses =>
        (all.forEach( ([obj, key], i) => obj[key] = responses[i]), obj) 
    );
}
Run Code Online (Sandbox Code Playgroud)

你会这样称呼它:

var loginResponsePromise = promiseRecursive({
    userprofile : getProfile(10),
    companyInfo : {
        company : getCompany(101),
        companyRelations : getPriviligedInfo(101)
    },
    groups : getGroups([5])
});
Run Code Online (Sandbox Code Playgroud)

function promiseRecursive(obj) {
    const getPromises = obj =>
        Object.keys(obj).reduce( (acc, key) =>
            Object(obj[key]) !== obj[key]
                ? acc
                : acc.concat(
                    typeof obj[key].then === "function"
                        ? [[obj, key]]
                        : getPromises(obj[key])
                  )
        , []);
    const all = getPromises(obj);
    return Promise.all(all.map(([obj, key]) => obj[key])).then( responses =>
        (all.forEach( ([obj, key], i) => obj[key] = responses[i]), obj) 
    );
}
Run Code Online (Sandbox Code Playgroud)
var loginResponsePromise = promiseRecursive({
    userprofile : getProfile(10),
    companyInfo : {
        company : getCompany(101),
        companyRelations : getPriviligedInfo(101)
    },
    groups : getGroups([5])
});
Run Code Online (Sandbox Code Playgroud)