使用包含循环

时间:2017-05-23 15:07:23

标签: javascript ecmascript-6 promise es6-promise

我一直试图弄清楚如何解决这个问题,但失败了。基本上我正在构建一个具有以下结构的数据树:

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);
            })
          })
        });
      })
    })
  })
编辑:我刚刚发现这个解决方案不能正常工作,我最终在树形数组中有重复项。也许有人可以告诉我如何以不同的方式处理这个问题。感谢。

2 个答案:

答案 0 :(得分:1)

有几个问题:

  • 您正在迭代最深层推动client个对象,这意味着您通常会获得太多的对象。
  • 当您使用map时,您应该将其用作push的替代方法,因为它会返回一个数组,从而无需使用push并导致更多功能代码。
  • libraries在每次[]次迭代中重置为map:这可能不正确,并且每次都会导致只有一个元素的数组,您需要获得尽可能多的元素map的元素正在迭代。
  • 使用返回promises的功能代码,而不是改变您的数据结构,这样最终您可以将完整的树作为承诺值并在最终的then回调中处理它。

这是一个应该有效的实现:

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"
          }
        ]
      }
    ]
  }
]

回复承诺

请注意,上面的代码使用带有表达式语法的箭头函数而不是语句块语法(因此在胖箭头=>之后没有括号)。胖箭头后面的表达式被计算为此箭头函数的 return 值。要使用语句块语法执行相同的操作,您可以将=> expression更改为=> { return expression; }

答案 1 :(得分:0)

如果您从.then()处理程序中返回承诺,那么这些承诺将被添加到链中,您可以通过监视顶级承诺来判断事情何时完成。此外,无论您在一个范围内创建多个承诺,您都可以监视所有这些承诺何时完成Promise.all()并返回一个主承诺。

以下是您在展示的代码中的工作原理。变更摘要:

  1. 您运行.map()并创建多个承诺的任何地方,请在生成的承诺数组中使用Promise.all(),以了解它们何时完成。

  2. .map()回调中,返回您创建的承诺,以便.map()的结果为一系列承诺,然后您可以Promise.all()使用。{/ p>

  3. 在运行任何异步操作的每个.then()处理程序中,返回一个监视异步操作的promise,然后将其链接到父promise。

  4. 在顶级承诺上使用.then()知道所有链接的内部承诺何时确实完成。

  5. 以下是如何将其应用于您展示的代码。

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