Dawn17
Dawn17

Reputation: 8297

Async Promise not getting the right value

function getProjects() {
  return new Promise(function(resolve, reject) {

    axios.get('url', {
      auth: {
        username: 'username',
        password: '   '
      }
    }).then(function(response) {
      let res = response.data.value;
      for (let i = 0; i < res.length; i++) {
        projects.push(res[i])
        resolve(projects);
      }
      console.log(projects)
    }).catch(function(error) {
      console.log(error)
    })
  })
}

getProjects()
  .then(function(proj) {
    console.log('proj', proj)

    function asnycItemAssignment() {
      return new Promise(function(resolve, reject) {
        for (let i = 0; i < proj.length; i++) {
          axios.get(`url`, {
              auth: {
                username: 'username',
                password: '   '
              }
            }).then(function(response) {
              //console.log(response.data.value)
              finalArr.push(response.data.value)
            })
            .catch(function(error) {
              console.log(error)
            })
        }

        resolve(finalArr)
      })
    }

    asnycItemAssignment()
      .then(function(res) {

        console.log('res', res)

        function flatten() {
          return new Promise(function(resolve, reject) {

            var myNewArray3 = [];
            for (var i = 0; i < res.length; ++i) {
              for (var j = 0; j < res[i].length; ++j) {

                console.log('pushed', i, j, res[i][j])
                myNewArray3.push(res[i][j]);
              }
            }

            console.log('finalArr', myNewArray3)
            resolve(myNewArray3)
          })
        }

        flatten()
          .then(function(value) {
            console.log('val', value)
          })

      })

  })
}

Here is what I am trying to do.

I am trying to fetch the list of projects from the API, store it into projects and resolve it to the Promise. Then again, I try to use the the names of the projects and use that for another API that gives me the data inside that project. This will store it into finalArr. I resolve finalArr this time.

finalArr is an array of arrays of objects. Something like [[{...}{...}][{...}]] That's why I wanted to flatten to make it like [{...},{...},{...},{...}].

However, in my asnycItemAssignment, the res which should give me the result of finalArr does not give me the full array with all values in it.

The code is quite messy, but I feel like I did it correctly. What am I doing wrong?

EDIT

async function getData() {
  let getProject =
    await axios.get('url', {
      auth: {
        username: 'username',
        password: '    '
      }
    })

  let projects = await getProject.data.value;

  projects.map(project => {
    let ItemAssignment = 
      axios.get(`url`, {
        auth: {
          username: 'username',
          password: '    '
        }
      })

    let values = await ItemAssignment.data.value
    console.log(values)
  })

  console.log('pr', projects)
}

getData()

Upvotes: 1

Views: 52

Answers (2)

Ethan Herbertson
Ethan Herbertson

Reputation: 117

One issue with your code is this:

  for (let i = 0; i < res.length; i++) {
    projects.push(res[i])
    resolve(projects)
  }

It almost never makes sense to call a promise's resolve() method in a for-loop (or any other looping construct), as you can only meaningfully call it once—or rather, the promise is resolved as soon as you call it the first time. This issue is hidden, in practice, in this code because you are modifying projects in-place each time you loop through the for-loop, and the for-loop may in-fact complete before you ever use the resolved promise for anything.

Resolving this first issue is as simple as moving resolve(projects) a couple lines further down:

  for (let i = 0; i < res.length; i++) {
    projects.push(res[i])
  }
  console.log(projects)
  resolve(projects)

Probably the main issue, though, is when and how you are calling resolve(finalArr) in here:

  return new Promise(function(resolve, reject) {
    for (let i = 0; i < proj.length; i++) {     
      axios.get(`url`, {                        
        auth: {                                 
          username: 'username',                 
          password: '   '                       
        }                                       
      }).then(function(response) {              
        //console.log(response.data.value)      
        finalArr.push(response.data.value)      
      })                                        
      .catch(function(error) {                  
        console.log(error)                      
      })                                        
    }                                           

    resolve(finalArr)                           
  })                                            

The pushes onto finalArr don't happen until after the individual axios.get calls resolve, but your call to resolve(finalArr) happens (essentially) immediately after all the axios.get calls are started.

Fixing this is a little trickier, as you'll want to wait until ALL the axios.get calls finish before resolving. One way to do that is with Promise.all():

function asnycItemAssignment() {
  for (let i = 0; i < proj.length; i++) {
    finalArr.push(
      axios.get(`url`, {
        auth: {
          username: 'username',
          password: '   '
        }
      }).then(function(response) {
        return response.data.value
      })
    )
  }
  return Promise.all(finalArr).catch(function(error) { console.log(error) })
}

As you admit, the code you have is pretty messy, and I agree with the other answers that you would do well to consider switching to the await/async syntax.

Upvotes: 0

Chris Cousins
Chris Cousins

Reputation: 1912

I really think you should read up on async/await. It makes code so much more readable when you depend on the result of one async operation to then do another. Some pseudocode is below, in order to get you going:

async function go() {
    try {
        const projects = await getProjects();
        projects.map(project => {
            const itemAssignments = await asnycItemAssignment(project);
            const flattened = await flatten(itemAssignments);
            console.log(flattened);
        }
    } catch (e) {
        console.error(e); // 💩
    }
}

Also, generically to see how axios can be used:

async getData() {
    return await axios(...);
}

Then you can use getData, like:

const r = await GetData();

Upvotes: 2

Related Questions