使用包含循环的嵌套承诺在JavaScript中创建树
我一直在想如何解决这个问题,但失败了。基本上,我正在构建具有以下结构的数据树:使用包含循环的嵌套承诺在JavaScript中创建树,javascript,ecmascript-6,promise,es6-promise,Javascript,Ecmascript 6,Promise,Es6 Promise,我一直在想如何解决这个问题,但失败了。基本上,我正在构建具有以下结构的数据树: tree = [ { 'title': 'Company 1', 'children': [ { 'title': 'Opportunity 1', 'children': [ { 'title': 'Library 1' }, // library {
tree = [
{
'title': 'Company 1',
'children': [
{
'title': 'Opportunity 1',
'children': [
{
'title': 'Library 1'
}, // library
{
'title': 'Library 2'
} // library
]
}, // opportunity
{
'title': 'Opportunity 2',
'children': [
{
'title': 'Library 1'
}, // library
{
'title': 'Library 2'
} // library
]
}, // opportunity
]
}, // client
...
]
我已经编写了以下填充树节点的代码,我只是不知道如何确定填充过程何时完成,树何时可以使用
你知道怎么处理吗
getList(getGetSitesURL(site)).then(r => {
r.d.results.map(site => {
var client = {};
client['title'] = site.Title;
getList(getGetSitesURL(site.ServerRelativeUrl)).then(r => {
r.d.results.map(site => {
var opportunity = {};
var opportunities = [];
opportunity['title'] = site.Title;
getLibrary(getGetLibrariesURL(site.ServerRelativeUrl)).then(r => {
r.d.results.map(lib => {
var library = {};
var libraries = [];
library['title'] = lib.Title;
libraries.push(library);
opportunity['children'] = libraries;
opportunities.push(opportunity);
client['children'] = opportunities;
tree.push(client);
})
})
});
})
})
})
编辑:我刚刚发现此解决方案无法按预期工作,结果在树数组中出现了重复项。也许有人能告诉我如何以不同的方式处理这个问题。谢谢。如果您从.then处理程序中返回承诺,那么这些承诺将添加到链中,您可以通过监控顶级承诺来判断事情何时完成。此外,在一个范围内创建多个承诺的任何地方,都可以监视何时使用Promise.all完成所有承诺,并返回该主承诺 下面是您展示的代码中的工作方式。更改摘要: 无论您在何处运行.map并创建多个承诺,请在生成的承诺数组中使用Promise.all,以了解这些承诺何时完成 在.map回调中,返回您创建的承诺,这样.map的结果将是一个承诺数组,您可以使用promise.all 在运行任何异步操作的每个.then处理程序中,返回一个监视该异步操作的承诺,以便将其链接到父承诺 使用一个。然后在顶级承诺上知道所有链接的内部承诺何时确实完成 下面是如何将其应用于您显示的代码
getList(getGetSitesURL(site)).then(r => {
// Use Promise.all() to know when the array of promises are all done
return Promise.all(r.d.results.map(site => {
var client = {};
client['title'] = site.Title;
// return this promise so .map() results in an array of promises
return getList(getGetSitesURL(site.ServerRelativeUrl)).then(r => {
// Use Promise.all() to know when the array of promises are all done
return Promise.all(r.d.results.map(site => {
var opportunity = {};
var opportunities = [];
opportunity['title'] = site.Title;
// return this promise so .map() results in an array of promises
return getLibrary(getGetLibrariesURL(site.ServerRelativeUrl)).then(r => {
r.d.results.map(lib => {
var library = {};
var libraries = [];
library['title'] = lib.Title;
libraries.push(library);
opportunity['children'] = libraries;
opportunities.push(opportunity);
client['children'] = opportunities;
tree.push(client);
});
});
}));
});
}));
}).then(function() {
// all done here
}).catch(function(err) {
// some error here
});
有几个问题: 您在迭代的最深处推送客户机对象,这意味着您通常会得到太多的客户机对象。 当您使用map时,应该将其用作push的替代方法,因为它返回一个数组,使得push变得不必要,并导致更多的功能代码。 在每次映射迭代中,库被重置为[]:这不可能是正确的,并且每次都会导致一个只有一个元素的数组,在这个数组中,您需要获得和映射迭代时一样多的元素。 与其改变数据结构,不如使用返回承诺的函数代码,以便最终得到完整的树作为承诺值,并可以在最终回调中处理它。 以下是一个应该有效的实现:
getList(getGetSitesURL(site)).then(r =>
Promise.all(r.d.results.map(site =>
getList(getGetSitesURL(site.ServerRelativeUrl)).then( r =>
Promise.all(r.d.results.map(subsite =>
getLibrary(getGetLibrariesURL(subsite.ServerRelativeUrl)).then(r => ({
title: subsite.Title,
children: r.d.results.map(lib => ({ title: lib.Title }))
}))
)).then(children => ({ title: site.Title, children}))
)
))
).then(tree => {
console.log(JSON.stringify(tree, null, 2));
});
输出类似于:
[
{
"title": "Company1",
"children": [
{
"title": "Opportunity 1",
"children": [
{
"title": "Library 1"
},
{
"title": "Library 2"
}
]
},
{
"title": "Opportunity 1",
"children": [
{
"title": "Library 1"
},
{
"title": "Library 2"
}
]
}
]
}
]
回报承诺
请注意,上面的代码使用带有表达式语法的箭头函数,而不是语句块语法,因此在fat arrow=>之后没有大括号。fat箭头后面的表达式作为该箭头函数的返回值进行计算。要使用语句块语法执行相同的操作,您需要将=>expression更改为=>{return expression;}。是否尝试过Promise。全部?我尝试过,但没有找到如何使其工作的方法。您的每个函数都需要返回一个Promise。请显示您的尝试。它确实返回了一个承诺,我正在使用fetch进行调用。不,您显示的代码中的任何函数回调都不会返回任何内容。非常感谢@trincot,它工作正常。不过,只有一个问题,这些库是从顶级站点而不是子站点中提取的。我想为每一个获取库:GetListGetSiteSurlsite.ServerRelativeUrl.Ah是的,我明白了。。。让我检查一下。我试图自己修复它,但同样不知道如何在不使用另一个嵌套映射函数的情况下实现这一点。我的JavaScript技能目前不是很好。谢谢你的帮助!谢谢@trincot,你救了我!所以,您根本不需要解释,通过切换到箭头函数,您隐式地返回了Promise.all在.then处理程序中的承诺。你错过了一次机会,无法解释/教授这一方法为什么有效,以及如何解决OP问题中的主要问题。很多新手都会完全忽略这个概念。谢谢你的帮助,尽管我意识到我的方法完全错了,嵌套的映射函数会生成很多重复项。@lukas-嗯,在你改变它之前,我回答了我面前的问题。我还解释了从内部返回承诺的概念,然后将承诺链接在一起,这样你就可以知道整个事情何时完成,而另一个答案根本无法解释。很高兴你最终得到了答案。