0

I have a problem, I tried to use async function to make API call but then() doesn't wait until the async function return the promise.

async function :

async function FgetFloorplansByFolder (idProject,idFolder, data = [], hasMore = false, lastSyncedAt = null) {
  axios.get(API_URL, {
    params:{
      'last_synced_at':lastSyncedAt
    },
      headers: {
        'Authorization': API_TOKEN,
        'Accept': 'application/json'
    }
  })

  .then((response) => {
    let XHasMore = response.headers['x-has-more'];
    let lastSyncedAt = response.headers['x-last-synced-at'];
    for(var i in response.data) {
      if(response.data[i].folder_id != null || response.data[i].folder_id == idFolder){
        data.push(response.data[i])
      }
    }
    if(XHasMore == 'true'){
       FgetFloorplansByFolder(idProject,idFolder, data, XHasMore, lastSyncedAt)
    }
    else {
      console.log(data);
      return data
    }
  })
  .catch((err) => {
    return Promise.reject(err)
  })
}

call of async function :

await FgetFloorplansByFolder(req.params.idProject, req.params.idFolder)
.then((result) => {
  console.log(result);
})
.catch((error)=>{
  console.log(error);
})

The expected result is : then function in the call wait until getFloorplansByFolders finish his recursive call and return data before print result in then. But then is printing undefined and doesn't wait until async function finish his call.

How can I do ?

CMICHEL
  • 3
  • 3
  • 3
    Don't mix `await` and `.then()` – Barmar Oct 22 '20 at 16:39
  • 3
    Your `FgetFloorplansByFolder` doesn't return the `axios.get()` result, so nothing else will wait for that call to complete nor would you get the response. – VLAZ Oct 22 '20 at 16:39
  • Is `response.data` an array? If so, `for-in` isn't the right tool to use to loop through it. [More in this answer](https://stackoverflow.com/questions/9329446/for-each-over-an-array-in-javascript/9329476#9329476). – T.J. Crowder Oct 22 '20 at 16:45

1 Answers1

2

Nothing in the code tells the function that it should wait for that promise to settle, so it doesn't.

In general, don't mix async/await with .then/.catch/.finally (though there are exceptions), use one or the other.

In this case, you can either

  1. Remove the async and just put return in front of the call to axios to return the promise chain; or

  2. Switch to using await within the function

(In both cases, I strongly urge you to remove the .catch handler that converts rejection into fulfillment with undefined; instead, let the caller see the rejection so they know the operation failed.)

#1 looks something like this (note comments):

// 1. No `async`
function FgetFloorplansByFolder (idProject,idFolder, data = [], hasMore = false, lastSyncedAt = null) {
  // 2. Return the promise chain
  return axios.get(API_URL, {
    params:{
      'last_synced_at':lastSyncedAt
    },
      headers: {
        'Authorization': API_TOKEN,
        'Accept': 'application/json'
    }
  })

  .then((response) => {
    let XHasMore = response.headers['x-has-more'];
    let lastSyncedAt = response.headers['x-last-synced-at'];
    for(var i in response.data) {
      if(response.data[i].folder_id != null || response.data[i].folder_id == idFolder){
        data.push(response.data[i])
      }
    }
    if(XHasMore == 'true'){
       // 3. Return the promise from the recursive call
       return FgetFloorplansByFolder(idProject,idFolder, data, XHasMore, lastSyncedAt)
    }
    else {
      console.log(data);
      return data
    }
  });
  // 4. Don't put a `.catch` here -- let the caller know the operation failed
}

#2 looks something like this:

async function FgetFloorplansByFolder (idProject,idFolder, data = [], hasMore = false, lastSyncedAt = null) {
  const response = await axios.get(API_URL, {
    params:{
      'last_synced_at':lastSyncedAt
    },
      headers: {
        'Authorization': API_TOKEN,
        'Accept': 'application/json'
    }
  });
  let XHasMore = response.headers['x-has-more'];
  let lastSyncedAt = response.headers['x-last-synced-at'];
  for(var i in response.data) {
    if(response.data[i].folder_id != null || response.data[i].folder_id == idFolder){
      data.push(response.data[i])
    }
  }
  if(XHasMore == 'true'){
     // 3. Return the result of the recursive call
     return FgetFloorplansByFolder(idProject,idFolder, data, XHasMore, lastSyncedAt)
  }
  else {
    console.log(data);
    return data;
  }
}
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • First solution works but only in case of the recursive call is not trigger. How to do if the recursive call is trigger ? – CMICHEL Oct 22 '20 at 16:54
  • @CMICHEL - Note the comment in the code: *"If this is an asynchronous operation, note that nothing is waiting for it to complete"* I didn't twig to the fact that that's the **same** function, so yes, it's asynchronous. I'll update it, but hopefully it's clear what you need to do? – T.J. Crowder Oct 22 '20 at 17:06