简体   繁体   中英

Async function call not complete in callback

I am trying to work with some async functions but my code, for example this.saveAsCSV(lists,"lists.csv"); seems to continue before the function completes. This is not exactly what I am doing but it is the shortened version that shows my issue. console.log(lists) has the correct data but I assume it is evaluated after the call

   public render(): void {
    (async () => {  
      await this.GetListsBySiteID("6a368204-0534-4ffb-8014-157524ca9d50").then(lists => {
        console.log(lists);
        this.saveAsCSV(lists,"lists.csv");      
      });
    })();
  }

  async GetListsBySiteID(id:string):Promise<string[]>
  {
    let lists1:string[] = [];

    await pnp.sp.site.openWebById(id).then(result => 
    {
      result.web.lists.get().then(lists => 
      {
        lists.forEach(list => {
          lists1.push(list.Title);
        });      
      })
    });

    return lists;
  }

How do I correct this?

The code is not tested, but this is the idea:

  1. Return a promise in the GetListsBySiteID function
  2. resolve the promise after you have the lists value populated
GetListsBySiteID(id:string):Promise<string[]> {
  return new Promise((resolve, reject) => {
    try {
      let lists:string[] = [];
      pnp.sp.site.openWebById(id).then(result => 
      {
        result.web.lists.get().then(lists => 
        {
          lists.forEach(list => {
            lists.push(list.Title);
          });    

          resolve(lists);
        })
      });
    } catch (ex) {
      reject(ex);
    }
  );
}

It's because in your GetListsBySiteID() function you have this code:

await pnp.sp.site.openWebById(id).then(result => 
{
  result.web.lists.get().then(lists => 
  {
    lists.forEach(list => {
      lists.push(list.Title);
    });      
  })
});

So what happens here is JavaScript is await ing for the pnp.sp.site.openWebById(id) Promise to complete before continuing. You have attached the .then() callback so it's being await ed too. Now the problem is in your .then() callback:

You are calling result.web.lists.get().then() but this Promise is not being await ed for. The solution is to add return keyword, like this:

await pnp.sp.site.openWebById(id).then(result => 
{
  return result.web.lists.get().then(lists =>  // <-- here I added return
  {
    lists.forEach(list => {
      lists.push(list.Title);
    });      
  })
});

So now the await will cause JavaScript to wait for the nested Promise also.

Here is a full async/await solution to this issue. Using await on result.web.lists.get() will wait for the process to finish first and then when resolved, finally giving you the correct lists

public render(): void {
  (async() => {
    const lists = await this.GetListsBySiteID("6a368204-0534-4ffb-8014-157524ca9d50")
    console.log(lists);
    this.saveAsCSV(lists, "lists.csv");
  })();
}

async GetListsBySiteID(id:string):Promise<string[]> {
  let lists1: string[] = [];
  const result = await pnp.sp.site.openWebById(id)
  const lists = await result.web.lists.get()
  lists1 = lists.map(x => x.Title);
  return lists1;
}

Please note that in your post, you are returning lists at the end inside GetListsBySiteID and that variable is not defined inside the function. So, if you want to return lists1 instead simply replace return lists; with return lists1; .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM