Node js Promise.All and Foreach在嵌套数组中



在带有打字稿的节点应用中,我需要通过数组迭代,并在循环中调用异步函数,以获取有关数组中每个项目的相关项目的信息。每个相关项目都调用该函数以在RelactionItems数组中获取其标题。

我能够检索第二级数组的承诺(相关标准),但不确定一旦顶级完成,如何实现A。

如何通过承诺实现我的目标。

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

您应该在顶级使用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 */})
}

,由于您正在使用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 : []
  });
}

注意我猜测一些基于用法的类型,您应该查看以确保它们正确。

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

最新更新