Search code examples
javascriptnode.jsweb3js

Can't update global variables from promise in NodeJS


I'm new to Nodejs, and I've been writing a Web3 handler for my contract, everything works good but the global variables don't update during the promise execution, they have no value even when I console.log after the Then.

...
var cityDb = {};
function gettingBalance() {

    return new Promise ( (resolve, reject) => { 

        Contract.totalSupply.call(function(error, result){
            if(!error)
                {

                resolve(result.toNumber());
                }
            else

                reject(error);
        });
    });
}


function gettingCities(cityNumber) {

    return new Promise ( (resolve,reject) => { 

        Contract.CityDB.call( cityNumber, (error, result) => {
            if(!error)
                {

                    resolve(result);

                }
            else
                reject(error);
        });

    });

}



gettingBalance()
    .then ( (result) => {
        console.log('Total after function: '+result);
        return result;
    })
        .then ( (totalSupply) => {
            console.log('loop data :'+totalSupply);

            // START SECOND PROMISE 

            for (let i=0; i <= totalSupply; i++) { 

                gettingCities(i) 
                    .then( (result) => {

                    cityDb[i] = {
                            cityName: result[0],
                            Population: result[1],
                            };


                        let j = i-1;
                        console.log('Loop ['+i+']'+ cityDb[i].cityName);

                    })
                    .catch( (error) => {
                        console.log(error);
                    });

                    if (i == totalSupply) { return;  }

            }


            // END SECOND PROMISE

        })
        .then ( (response) => {
            console.log('Test promise loop: '+ cityDb[2]);
        })
        .catch( (err) => {
            console.log('loop error: '+err);
        });

Log results :

Total supply after function: 3
loop data :3
Test promise loop: undefined
Loop [0]0x4e657720596f726b000000000000000000000000000000000000000000000000
Loop [1]0x5061726973000000000000000000000000000000000000000000000000000000
Loop [2]0x4e61646f72000000000000000000000000000000000000000000000000000000
Loop [3]0x0000000000000000000000000000000000000000000000000000000000000000

Why is test promise loop undefined? The cityDB isn't getting update from the loop, but the loop works perfectly as intended.


Solution

  • The problem was that you weren't chaining promises correctly. Your last then wasn't waiting until all your gettingCities calls were done. For that you can use Promise.all

    gettingBalance()
        .then((result) => {
            console.log('Total after function: ' + result);
            return result;
        })
        .then((totalSupply) => {
            console.log('loop data :' + totalSupply);
    
            // START SECOND PROMISE 
            const promises = [];
    
            for (let i = 0; i < totalSupply; i++) {
                // We push gettingCities promises into the array
                promises.push(gettingCities(i));    
            }
    
            // We pass gettingCities promises into Promise.all
            return Promise.all(promises);
    
        })
        .then((results) => {
    
            // All gettingCities results
            // We loop through each result and fill cityDb
            results.forEach((result, i) => {
    
                cityDb[i] = {
                    cityName: result[0],
                    Population: result[1],
                };
    
                console.log('Loop [' + i + ']' + cityDb[i].cityName);
            })
    
            console.log('Test promise loop: ' + cityDb[2]);
        })
        .catch((err) => {
            console.log('loop error: ' + err);
        });
    

    You can remove the global cityDb and just handle it in the last .then

    .then((results) => {
    
        // gettingCities results
        const cityDb = {};
        results.forEach((result, i) => {
    
            cityDb[i] = {
                cityName: result[0],
                Population: result[1],
            };
    
            console.log('Loop [' + i + ']' + cityDb[i].cityName);
        })
    
        console.log('Test promise loop: ' + cityDb[2]);
    })