1

I know that javascript is asynchronous and if i make a for loop after .then then the loop ends and only then do the object promise become clear, but I can't for the life of me fix this code snippet, maybe someone can help me. My goal is to loop and check if variable ans, which I take from a function is equal to variable account and if so then print out information that I get from other functions.

loopforCetrs : function() {
        var num;
        var account = web3.currentProvider.selectedAddress;

        App.contracts.StudentState.deployed().then(function (instance) {
        return instance.showNumOfContracts();
      }).then(function (numOfCert) {
          num = numOfCert;

            var wrapper = document.getElementById("myHTMLWrapper");

            for (var i = 0; i < num; i++) {
                App.ShowAddress(i).then(function (ans) {

                    if(ans == account) {
                        alert(ans+' Hello');
                        alert(account+' Hi')
                        App.ShowFName(i).then(function (ans) {
                            wrapper.innerHTML += '<span class="test">Name: ' + ans + ' </span><br/><br/>';
                        })

                        App.ShowLName(i).then(function (ans) {
                            wrapper.innerHTML += '<span class="test">Surname: ' + ans + ' </span><br/><br/>';
                        })

                        App.ShowInstName(i).then(function (ans) {
                            wrapper.innerHTML += '<span class="test">Institutions name: ' + ans + ' </span><br/><br/>';
                        })

                        App.ShowAddress(i).then(function (ans) {
                            wrapper.innerHTML += '<span class="test">Users address: ' + ans + ' </span><br/><br/>';
                        })

                        App.ShowCourseName(i).then(function (ans) {
                            wrapper.innerHTML += '<span class="test">Course name: ' + ans + ' </span><br/><br/>';
                            wrapper.innerHTML += '<span class="test"></span><br/><br/>';
                        })
                    }
                })

            }

      })
    },

EDIT 1: This was the code i used before and it did the job, but now I wanted to add 1 thing and hit a wall.

loopforCetrs : function() {
        var num;
        var account = web3.currentProvider.selectedAddress;

        App.contracts.StudentState.deployed().then(function (instance) {
        return instance.showNumOfContracts();
      }).then(function (numOfCert) {
          num = numOfCert;

            var wrapper = document.getElementById("myHTMLWrapper");

            for (var i = 0; i < num; i++) {

                App.ShowFName(i).then(function (ans) {
                    wrapper.innerHTML += '<span class="test">Name: ' + ans + ' </span><br/><br/>';
                })

                App.ShowLName(i).then(function (ans) {
                    wrapper.innerHTML += '<span class="test">Surname: ' + ans + ' </span><br/><br/>';
                })

                App.ShowInstName(i).then(function (ans) {
                    wrapper.innerHTML += '<span class="test">Institutions name: ' + ans + ' </span><br/><br/>';
                })

                App.ShowAddress(i).then(function (ans) {
                    wrapper.innerHTML += '<span class="test">Users address: ' + ans + ' </span><br/><br/>';
                })

                App.ShowCourseName(i).then(function (ans) {
                    wrapper.innerHTML += '<span class="test">Course name: ' + ans + ' </span><br/><br/>';
                    wrapper.innerHTML += '<span class="test"></span><br/><br/>';
                })
            }

      })
    },
TylerH
  • 20,799
  • 66
  • 75
  • 101
RokasPo
  • 53
  • 6
  • yikes with that code. I see major issue with infamous for loop when `i` is not what you think it is – epascarello Dec 11 '19 at 22:59
  • https://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example – epascarello Dec 11 '19 at 23:01
  • yeah when the loop ends i is then the maximum value, I think the solution would be to avoid loops all together, but I just can't figure out how to do that – RokasPo Dec 11 '19 at 23:02
  • The link above shows you how to fix that problem. My question as a developer is WHY is there so many asynchronous calls? It is code smell which is not good. – epascarello Dec 11 '19 at 23:04
  • The structure is all wrong. Why are there individual async calls just to get their first and last name? This is like, fetching the first name from mongodb, then making another query to fetch the last name. – alex067 Dec 11 '19 at 23:07
  • well didn't know any way to put it into reality, but if only we remove the comparison of ```ans``` and ```answer``` and the first overlapping function that calls for the address, everything works like a charm. Edited to clarify what I mean – RokasPo Dec 11 '19 at 23:08

1 Answers1

3

Use promises the way they were intended. That code is frankly nightmarish to look at when it could be so much simpler with ES6 async/await and template literals:

loopforCetrs : async function() {
    const account = web3.currentProvider.selectedAddress;
    const numOfCert = await (await App.contracts.StudentState.deployed()).showNumOfContracts());
    const wrapper = document.getElementById("myHTMLWrapper");

    for (let i = 0; i < numOfCert; i++) {
        if((await App.ShowAddress(i)) == account) {
            //alert(ans+' Hello'); no more ans
            alert(account+' Hi');
            wrapper.innerHTML += `<span class="test">Name: ${await App.ShowFName(i)} </span><br/><br/>`;
            wrapper.innerHTML += `<span class="test">Surname: ${await App.ShowLName(i)} </span><br/><br/>`;
            wrapper.innerHTML += `<span class="test">Institutions name: ${await App.ShowInstName(i)} </span><br/><br/>`;
            wrapper.innerHTML += `<span class="test">Users address: ${await App.ShowAddress(i)} </span><br/><br/>`;
            wrapper.innerHTML += `<span class="test">Course name: ${await App.ShowCourseName(i)} </span><br/><br/>`;
            wrapper.innerHTML += `<span class="test"></span><br/><br/>`;
        }
    }
}

This way, you won't run into issues with i being the wrong value when the callbacks have resolved since everything is awaited and is guaranteed to fully resolve with in that loop iteration before i has changed values.

There's still a lot of redundancy but my preferred way to fix that would be to add methods to App that return more than a measly single piece of information. Have one that returns all relevant information instead and you reduce another 5 lines of redundant code and greatly improve performance and efficiency.

Klaycon
  • 10,599
  • 18
  • 35
  • Oh that really looks and feels a lot better, I will try to do more research into the await function, but the numOfCert line is still problematic. – RokasPo Dec 11 '19 at 23:17
  • @RokasPo Yeah, my bad, misplaced a parenthesis. I've edited it, should work now. – Klaycon Dec 11 '19 at 23:18
  • Thank you a lot, I also might want to add that I don't intend to break after the first finding, but you've been a huge help! – RokasPo Dec 11 '19 at 23:26
  • 1
    @RokasPo Glad to be of help, as to the break statement I must have misinterpreted your question title. Edited it out so it's only the relevant stuff left. – Klaycon Dec 11 '19 at 23:27