简体   繁体   中英

How to wait for a promise to resolve before the next iteration in for loop

I have got two data tables I want to query some data from, so the way i thought about doing it is fetch url and based on a field from list, I do fetch(url) once more to get related data from another data table and I want to append them together to display on the browser. The issue here is that for loop iteration doesn't wait until the previous fetch is finished. I am using django_restframework, and it is me trying to fetch data by passing criteria(variables) through urls. can anyone help?

var url = 'http://127.0.0.1:8000/creditor-detail/'+pmt_id+'/supplier/'+crm_spplier_id+'/'

var results = fetch(url)
      .then((resp) => resp.json())
      .then(function(item){ 

        var list = item
        for (var i in list){

                    getCustomer(list[i].customer_id)
                    .then(function test(user) {
                    return user[0].customer_name
                   
                  });

                var spmt = `
                    <tr id="data-row-${i}">
                        <td>${list[i].po_no}</td>
                        <td>${list[i].amount}</td>                  
                        <td>${I want return value[user[0].customer_name]}</td>
                    </tr>
                `
                wrapper.innerHTML+= spmt
        }
      })





  function getCustomer(customer_id){
    var url = 'http://127.0.0.1:8000/user-detail/'+customer_id+'/'

    var results = fetch(url)
                  .then((resp) => resp.json())
                  .then(function(item){

                      return item       
                  })
  return results
}

I have changed to:

    function test() {
      const url = 'http://127.0.0.1:8000/creditor-detail/'+pmt_id+'/supplier/'+crm_supplier_id+'/'
      let promises = [];

      const results = fetch(url)
      .then(resp => resp.json())
      .then(function (item) {

        var list = item;
   
        for (var i in list) {
          promises.push(getCusotmer(list[i].customer_id));
          console.log(list[i].customer_id)

        }
      })
      
      Promise.all(promises)
          .then((results) => {
            console.log("All done", results);
          })
          .catch((e) => {
            
            console.log(err)
          });
    }
    
    


    function getCusotmer(customer_id) {
    
    return new Promise((resolve, reject) => {
      const url = 'http://127.0.0.1:8000/customer-detail/' + customer_id+ '/';
      fetch(url)
        .then(resp => resp.json())
        .then((item) => resolve(item))
        .catch((err) => {

          console.log(err)
          
          reject(err)
        })
    })
  }

  test();

And the console looks like this:

All done []length: 0__proto__: Array(0) 1466 1663

I thought based on the promise logic, all done should have been read in the end, am I missing anything here?

It's hard to understand the first time, but here I go. The simple answer is "You can't do that", javascript works with an 'event loop', it's like a thread containing all the tasks javascript is going to do, when you use an asynchronous task like 'search' it escapes the 'event loop' for being asynchronous. But the 'for loop' is not asynchronous so it will be processed in the 'Event Loop'. This means that 'fetch' will exit the 'Event Loop' and when its request is completed it will return to the 'Event Loop', in this moment, the 'for loop' was terminate.

But don't worry, you can solve it, how? well, you can iterate the loop and save a new array of promise, await for all of them will complete and in this moment create your 'tr' row

Its an example with your code: The first function could be like this:

const promises = [];
fetch(url)
  .then(resp => resp.json())
  .then((item) => {
    const list = item;
    for (let i in list) {
      promises.push(getCustomer(list[i].customer_id))
    }
    Promise.all(promises).then((resolveAllData) => {
      //Do all that you need with your data
      //Maybe you can use a for loop for iterate 'responseAllData
    });
  }).catch((err) => {
    //manage your err
  })


And the second function could be like this:

function getCustomer(customer_id) {
  return new Promise((resolve, reject) => {
    const url = 'http://127.0.0.1:8000/user-detail/' + customer_id + '/';
    fetch(url)
      .then(resp => resp.json())
      .then((item) => resolve(item))
      .catch((err) => {
         //manage your err
         reject(err)
      })
  })
}

A recommendation, learn how JavaScript works and its asynchronism, try not to use 'var', to get better performance and have no problems with scope

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