简体   繁体   中英

How to set the call back in WEB3

I have two functions in a blockchain contract to get the investors and funds for an address and tried to save that in Excel.

1st Function To get the list of investors:

getInvestorsList()

2nd Function This will take the investor address as input and returns the investor's address and the funds saved for that address:

getInvestorsAndBalances(address investorAddress)

I was able to get the list of investors and the funds sponsored by them using the functions "getInvestorsList" and "getInvestorsAndBalances".

Question

  1. The below snippet, which convert the data to excel has to executed only when the function "getInvestorsAndBalances" executes completely for all investors. But this code is executed even before the call to the contract completes. Hence I am not getting the values from the blockchain to the below snippet.

How to make the below code wait for the successful completion of the function "getInvestorsAndBalances" ?

                dataSample = dataSample + "]";
                console.log("dataSample: " + dataSample);
                //var dataSample = [{"address": "abc","balance": "21.22"}]; 
                const xls = new XlsExport(dataSample,  'Example WB');  
                xls.exportToXLS('export.xls')  

Complete Code

    crowdSaleContractObj.getInvestorsList(function(error, result){
            if(!error)
                {    
                    for (i=0; i < result.length; i++) {  

                        crowdSaleContractObj.getInvestorsAndBalances(result[i],function(error, result1){
                        console.log(i);

                        if(!error)
                            {      
                                console.log(i + " - Address : " + result1[0]+ ",  Balance : " + result1[1]);
                                element = " {\"address\": " + result1[0] + ",balance:" + result1[1] + "},";
                                console.log("element: " + element);
                                dataSample = dataSample + element;
                            }
                        else
                            console.error(error);
                        });   
                    }

                    dataSample = dataSample + "]";
                    console.log("dataSample: " + dataSample);
                    //var dataSample = [{"address": "abc","balance": "21.22"}]; 
                    const xls = new XlsExport(dataSample,  'Example WB');  
                    xls.exportToXLS('export.xls')  

                }
            else
                console.error(error);
    });  

Here's a version of your code that works:

crowdSaleContractObj.getInvestorsList(function(error, results) {
  if (!error) {
    const promises = results.map(function(result, i) {
      return new Promise((resolve, reject) => {
        crowdSaleContractObj.getInvestorsAndBalances(result[i], function(
          error,
          result1
        ) {
          console.log(i);

          if (!error) {
            console.log(
              i + " - Address : " + result1[0] + ",  Balance : " + result1[1]
            );
            resolve(result1);
          } else {
            console.error(error);
            reject(error);
          }
        });
      });
    });

    Promise.all(promises)
      .then(function(results1) {
        results1.forEach(r => {
          element = ' {"address": ' + r[0] + ",balance:" + r[1] + "},";
          console.log("element: " + element);
          dataSample = dataSample + element;
        });
        dataSample = dataSample + "]";
        console.log("dataSample: " + dataSample);
        //var dataSample = [{"address": "abc","balance": "21.22"}];
        const xls = new XlsExport(dataSample, "Example WB");
        xls.exportToXLS("export.xls");
      })
      .catch(function(error) {
        console.error(error);
      });
  } else console.error(error);
});
  1. Instead of a for loop, I'm using Array.map to transform the results into an array of promises which resolve with the value returned to the callback in getInvestorsAndBalances
  2. In the next step, I'm calling Promise.all on this array of promises; this causes the code in the then method to be executed only after all the investors and balances have been retrieved asynchronously

Improving the Code

I've taken the liberty to refactor your code a bit to use modern language features and fix some mistakes:

crowdSaleContractObj.getInvestorsList((error, results) => {
  if (error) {
    console.error(error);
    return;
  }
  const promises = results.map(
    (result, i) =>
      new Promise((resolve, reject) => {
        crowdSaleContractObj.getInvestorsAndBalances(
          result[i],
          (error, result1) => {
            if (error) {
              reject(error);
              return;
            }
            resolve(result1);
          }
        );
      })
  );

  Promise.all(promises)
    .then(results1 => {
      const dataSample = `[${results1
        .map(r => `{"address": "${r[0]}", "balance": ${r[1]}}`)
        .join(", ")}]`;
      const xls = new XlsExport(dataSample, "Example WB");
      xls.exportToXLS("export.xls");
    })
    .catch(function(error) {
      return console.error(error);
    });
});
  1. I'm using arrow functions instead of function declarations for more consise code
  2. I'm using the early return pattern (check if there's an error, then immediately return from the function) to avoid too much deep nesting of if/else statements
  3. I'm declaring variable dataSample with const ; you didn't declare it at all, neither i or element , which made them global variables – this is a bad practice
  4. I'm using template strings to construct the data string for XLS export
  5. I've fixed formatting issues in your data string – it was not generating valid JSON because you got confused with the quotes and commas
  6. I'm using Array.map to create the dataSample string, combined with Array.join to avoid the problem of having a trailing comma at the end of the data (which caused invalid JSON format)
  7. I've removed the console statements, assuming you just used these for debugging

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