Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/381.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 用嵌套承诺解析对象的漂亮方法?_Javascript_Express_Promise_Loopbackjs_Bluebird - Fatal编程技术网

Javascript 用嵌套承诺解析对象的漂亮方法?

Javascript 用嵌套承诺解析对象的漂亮方法?,javascript,express,promise,loopbackjs,bluebird,Javascript,Express,Promise,Loopbackjs,Bluebird,在构建自定义端点时,我通常需要解析包含承诺的复杂对象 如需说明,请以以下示例为例: 给定已知用户id、employeeId和MemberGroupSID(数组): 此逻辑适用于只返回其值的同步函数。但是对于返回承诺的函数,我必须手动将它们全部推送到一个数组中,以确保在使用最终对象之前解决它们 我发现上面的代码很容易理解,我正在寻找一个签名,该签名给出了其中的一部分,同时仍然确保在将最终对象发送给客户机之前,承诺已得到解决 问题不是让它工作,而是让它美观易读 最好的答案是确保将值返回到对象中的预期

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

如需说明,请以以下示例为例:

给定已知用户id、employeeId和MemberGroupSID(数组):

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

我发现上面的代码很容易理解,我正在寻找一个签名,该签名给出了其中的一部分,同时仍然确保在将最终对象发送给客户机之前,承诺已得到解决

问题不是让它工作,而是让它美观易读

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


或者,如果我没有抓住要点,并且完全错误地看待这一点,我应该如何看待它呢?

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

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) 
    );
}
你可以这样称呼它:

var loginResponsePromise = promiseRecursive({
    userprofile : getProfile(10),
    companyInfo : {
        company : getCompany(101),
        companyRelations : getPriviligedInfo(101)
    },
    groups : getGroups([5])
});
Promise.all([
    getProfile(id),
    getCompany(employeeId),
    getPriviligedInfo(employeeId),
    getGroups(memberGroupsIds)
])
.then(response => {

    const [ userprofile, company, companyRelations, groups ] = response

    const loginResponse = {
      userprofile,
      companyInfo : {
        company,
        companyRelations
      },
      groups
    }
})
.catch(err => console.error(err))
功能PromiserExecutive(obj){
const getPromises=obj=>
Object.key(obj).reduce((acc,key)=>
对象(对象[键]!==对象[键]?acc
:acc.concat(对象[key]的类型)。然后==“函数”?[[obj,key]]
:getPromises(obj[key]))
, []);
const all=getPromises(obj);
返回Promise.all(all.map(([obj,key])=>obj[key])。然后(responses=>
(all.forEach(([obj,key],i)=>obj[key]=responses[i]),obj)
);
}
//返回函数示例
const wait=ms=>new Promise(resolve=>setTimeout(resolve,ms)),
getProfile=id=>wait(100),
getCompany=employeeId=>wait(200),
getPriviligedInfo=employeeId=>wait(500),
getGroups=memberGroupsIds=>wait(400);
//传递给“promiseRecursive”函数的示例输入
const loginResponsePromise=PromiserExecutive({
userprofile:getProfile(10),
公司信息:{
公司名称:getCompany(101),
公司关系:getPriviligedInfo(101)
},
组:getGroups([5])
});
//显示已解析的对象
然后(o=>console.log(o))

。作为控制台包装{max height:100%!important;top:0;}
我通常使用Bluebird的
join来解决这种情况:


使用新的ES6功能,我将编写如下内容:

var loginResponsePromise = promiseRecursive({
    userprofile : getProfile(10),
    companyInfo : {
        company : getCompany(101),
        companyRelations : getPriviligedInfo(101)
    },
    groups : getGroups([5])
});
Promise.all([
    getProfile(id),
    getCompany(employeeId),
    getPriviligedInfo(employeeId),
    getGroups(memberGroupsIds)
])
.then(response => {

    const [ userprofile, company, companyRelations, groups ] = response

    const loginResponse = {
      userprofile,
      companyInfo : {
        company,
        companyRelations
      },
      groups
    }
})
.catch(err => console.error(err))

可能有趣的是,
Promise.all()
保持输入参数的顺序,而不取决于哪个先解析。因此,在下一步中,使用,代码看起来是同步的。

var loginResponse=Promise.all([getProfile(Id)、getCompany(EmployeeId)、getPriviligedInfo(EmployeeId)、getGroups(MemberGroupsIds)]。然后([userprofile,companyRelations,groups])=>({userprofile,companyInfo:{companyRelations},groups})-当然,您不能仅使用
loginResponse
作为值,因为这是一个承诺。。。所以,应该使用
loginResponse.then(obj=>{…在这里做事情…})是的,这是可行的,但并不能真正说明返回对象是如何构造的,或者随着需求的扩展,如何添加新的子对象(将其用于10倍于示例大小/复杂度的对象)很明显,在这样一行代码中,它并不漂亮-您想要工作代码还是漂亮代码-我想您可以使用async/await使它漂亮(我想要漂亮的代码:)正如我所说,问题不是让它工作,而是让它的语法与示例对象的语法有点类似。我不相信没有人建议它。在我看来,真正的方法是使用一个调用将所需的所有数据返回到服务器,而不必等待4个单独的调用完成。没有人说漂亮的代码就是聪明的代码。这看起来很有希望(没有双关语)。明天我将试用它,但defo是公认解决方案的有力候选者(promiseRecursive helper的语法对我来说有点混乱,但我会理解它,并且应该可以通过使其递归来使它更深入)。loginResponse返回已解析的传递对象的承诺,因此实际上不是响应,而是响应的承诺(只是命名)。我可能会实现为一个全局帮助器,并执行类似于
promiseRecursive({loginObj})的操作。然后(o=>loginResponse=o)
,除非有理由不这样做?实际上,函数返回一个承诺,因此需要对其应用
然后
,以获得已解析的对象(另请参见代码段)。请注意,任何解决方案都必须以异步方式将已解析的对象交给您。不可能创建一个以同步方式返回结果的函数,因为很明显,内部承诺只以异步方式提供它们的最终值。你说让它递归:它是递归的。不知道你还想说什么?谢谢@trincot是的。我得到了“必须异步返回”的答案,只是为了帮助我自己的理解而重申:)嗯。。我想我现在看到了递归(我从来没有真正使用过三元运算和ES6缺少括号,这对我来说还是有点不寻常)。漂亮的小代码!现在,我在文本中更清楚地缩进了三元运算符,并为