【问题标题】:Node JS Promise.all and forEach in nested Array嵌套数组中的节点 JS Promise.all 和 forEach
【发布时间】:2018-05-11 21:02:54
【问题描述】:

在带有打字稿的 Node 应用程序中,我需要遍历一个数组,并在循环内调用一个异步函数来获取有关数组中每个项目的相关项目的信息。为每个相关项调用该函数以获取其在 relatedItems 数组中的标题。

我能够检索第二级数组(relatedItems)的承诺,但不知道如何在顶级完成后实现一个 then。

如何通过 promise.all 实现我的目标。

var Inputarray = [
    {   Category: "cat1"
        relatedItems: [
            {id: "1"},
            {id: "2"},
            {id: "3"}
        ]
    },
    {
        Category: "cat2"
        relatedItems: [
            {id: "1"},
            {id: "2"},
            {id: "3"}
        ]
    }
];


var wantedresult= [
    {   Category: "cat1"
        relatedItems: [
            {Title: "xxx"},
            {Title: "yyy"},
            {Title: "zzz"}
        ]
    },
    {
        Category: "cat2"
        relatedItems: [
            {Title: "ttt"},
            {Title: "kkk"},
            {Title: "mmm"}
        ]
    }
];


private GetAllRelattedItems(data: IListItem[]): any{  


      let rendredItems: RelatedItem[] = new Array();



              data.forEach(item => {


                  let relatedItemsinfos : relatedItemInfos[]=item.Children;

                     let localTab:relatedItem[]=new Array();

                      let newItem = {
                              Category:item.Category,              
                              Children: []           
                      };

                    var promises = [];
                    relatedItemsinfos.forEach(relatedItemsInfositem =>{
                        promises.push(this.GetRelatedItem(relatedItemsInfositem.WebId,relatedItemsInfositem.ListId,relatedItemsInfositem.ItemId));
                    });
                     Promise.all(promises).then(function(response) {

                        response.forEach(obj=>{
                          let newNode: relatedItem ={
                            Title :Obj.Title,

                          };

                          newItem.Children.push(newNode);

                        });


                        rendredItems.push(newItem);


                    });


              });

} 


private  GetRelatedItem(id:string) : Promise<relatedItem> {

  return new Promise((resolve) => {

    pnp.sp.site.openWeb()
    .then(web => {
    //this.getWeb()
    //.then((web) => {

      return web.web.lists.getList().get();     //w.web.lists.getById("").get().then(r => {
    })
    .then((list) => {
      return this.getItem(list,id);
    })
    .then((item) => {

      resolve(item);
    });
  });
}

【问题讨论】:

    标签: node.js typescript npm promise


    【解决方案1】:

    您应该在顶层使用Promise.all 并返回数据数组中每个项目的承诺:

    private GetAllRelattedItems(data: IListItem[]): any {
      //..
      let allData = data.map(item => {
        //..
        return Promise.all(promises).then(function (response) {
          //..
        });
      });
      Promise.all(allData).then (_=> { /* After all data is retrieved */})
    }
    

    【讨论】:

      【解决方案2】:

      由于您使用的是 Typescript,因此更好的方法是利用 async/await 使代码更具可读性:

      private async GetAllRelattedItems(data: IListItem[]): Promise<RendredItem[]> {
        let allData = data.map(async item => {
          let relatedItemsinfos: relatedItemInfos[] = item.Children;
      
          let localTab: relatedItem[] = new Array();
      
          let newItem = {
            Category: item.Category,
            Children: []
          };
      
          var response = await Promise.all(relatedItemsinfos.map(relatedItemsInfositem => {
            return this.GetRelatedItem(relatedItemsInfositem.WebId);
          }));
      
          newItem.Children = response.map(entry => ({
              Title: entry.value[0].Title,
              FileLeafRef: entry.value[0].FileLeafRef,
              Modified: entry.value[0].Modified,
              FileRef: entry.value[0].FileRef,
              FieldValuesAsText: {
                FileRef: entry.value[0].FileRef,
              }
          }));
          return newItem;
      
        });
        var result = await Promise.all(allData);
        // After all results are done
        return result
      }
      
      private async GetRelatedItem(id: string): Promise<{ value: relatedItem[] }> {
          const web = await pnp.sp.site.openWeb()
          const list = await web.web.lists.getList().get();     //w.web.lists.getById("").get().then(r => {
          return await this.getItem(list,id);
      }
      
      // Placeholder
      public getItem(list: any[], id: string ): Promise<{ value: relatedItem[] }>{
        return Promise.resolve({
          value : []
        });
      }
      

      注意我根据使用情况猜测了一些类型,您应该检查以确保它们是正确的。

      【讨论】:

      • 使用异步等待我得到结果。谢谢
      • @user9019334 如果有用,请不要忘记标记为已回答并投票 :)
      • 我想在我的 getItem 函数中调用另一个异步函数。该函数将项目标题作为参数并返回项目大小,因此它必须等待执行 getitem 以获取每个项目的标题。如何使用 await/async 修改我的代码以添加此功能。目标是获得最终的输出项模型:item {title:"";modified:"";itemsize:"";}。
      • 如果您将getItem 函数标记为async,您可以使用await otherFunction("Title"),如果您发布代码,我可能会为您提供更多帮助。不要忘记投票并标记为已回答!
      • private GetItemSize(title: string): Promise{ Let url:string ; // title 的简单函数 // 使用 rest 异步检索项目大小,响应是大小。 return this.context.spHttpClient.get(url,SPHttpClient.configurations.v1).then((response: Response)=>{ return response.json(); });其余调用仅返回尺寸信息,但我想返回具有尺寸属性的相关项目模型。
      【解决方案3】:
      private async GetAllRelattedItems(data: IListItem[]): Promise<RendredItem[]> {
      
          let allData = data.map(async item => {
      
            let relatedItemsinfos: relatedItemInfos[] = item.Children;
      
            let localTab: relatedItem[] = new Array();
      
            let newItem = {
              Category: item.Category,
              Children: []
            };
      
            var response = await Promise.all(relatedItemsinfos.map(relatedItemsInfositem => {
              return this.GetRelatedItem(relatedItemsInfositem);
            }));
      
            newItem.Children = response.map(entry => ({
                Title: entry.value[0].Title,
                FileLeafRef: entry.value[0].FileLeafRef,
                Modified: entry.value[0].Modified,
                FileRef: entry.value[0].FileRef,
                FieldValuesAsText: {
                  FileRef: entry.value[0].FileRef,
                }
            }));
            return newItem;
      
          });
          var result = await Promise.all(allData);
          // After all results are done
          return result
        }
      
      
      
      private async  GetRelatedItem(relatedItemsInfositem) : Promise<any> {
        const web = await pnp.sp.site.openWebById(relatedItemsInfositem.WebId);
        const list = await web.web.lists.getById(relatedItemsInfositem.ListId).get();     
        return await this.getItem(list,relatedItemsInfositem.ItemId);
        // here i would like to call GetItemSize that is async and that take return the size as a number but i would like to return the whole item model 
      }
      
      public getItem(list: any, itemId: string): Promise<any>{
        let url: string;
        if(list.ParentWebUrl !='/'){
          url= list.ParentWebUrl + "/_api/web/lists/getbytitle('"+list.Title+"')/items?$select=FileLeafRef,FileRef,Title,File/ServerRelativeUrl,Modified,FieldValuesAsText/FileRef&$expand=File&$expand=FieldValuesAsText&$filter=Id eq "+itemId; 
      
        }
        else url="/_api/web/lists/getbytitle('"+list.Title+"')/items?$select=FileLeafRef,FileRef,Title,File/ServerRelativeUrl,Modified,FieldValuesAsText/FileRef&$expand=FieldValuesAsText&$expand=File&$filter=Id eq "+itemId;
      
        return this.context.spHttpClient.get(url,SPHttpClient.configurations.v1).then((response: Response)=>{  
          return response.json();  
        });  
      
      
      }
      
      private async GetItemSize(title: string): Promise<relatedItem>{ 
      let url:string ; 
      let response‌​ = await this.context.spHttpClient.get(url ,SPHttpClient.configuration‌​s.v1); 
      // Asuming the json has the shape of relatedItem : Here the response is just a number and not shaped RelatedItem the goal is to return the whole relatedItem with size information.
         return <relatedItem>response.json(); }
      

      【讨论】:

        猜你喜欢
        • 2015-10-03
        • 2018-01-09
        • 2021-07-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-09-08
        • 2016-11-20
        相关资源
        最近更新 更多