1

In my contract there are 2 functions, the first one returns an array size and other one returns data from the array with index passed as a parameter.

In my web3 script I'm trying to read array size and when done, perform loop, put data into the array, sort data from highest to lowest value and display it on the screen.

The problem is data is asynchronous, for now it displays data before finishing the loop. I need to wait until the loop is complete. How can I change this code to make it working?

The following code is inside async function:

const total = await promisify(cb => platform.getArraySize(cb));
items = [];
for(let i = 0; i < total; i++)
{
    // wait??
    platform.getData(i, function(error, result)
    {
        items[i] = [result[0].toNumber(), result[1].toNumber()];
        items = items.sort(function(a, b)
        {
            return b[1] - a[1]
        });
    });
}
for(let i = 0; i < items.length; i++)
{
    $("#container").append("<div>a: " + items[i][0] + ", b: " + items[i][1] + "</div>");
}

closed as off-topic by Ismael, Briomkez, shane, Achala Dissanayake, Richard Horrocks Nov 30 '18 at 8:35

This question appears to be off-topic. The users who voted to close gave this specific reason:

  • "This question does not appear to be about Ethereum, the decentralized application platform and smart contract enabled blockchain, within the scope defined in the help center." – Ismael, Briomkez, shane, Achala Dissanayake, Richard Horrocks
If this question can be reworded to fit the rules in the help center, please edit the question.

0

A callback can be adapted into a promise, then the await keyword can be used to pause the loop until the callback cause the promise to complete, for example:

for(let i = 0; i < total; i++)
{
    const {error, result} = await new Promise((resolve) => platform.getData(i, (e, r) => {e,r});
    items[i] = [result[0].toNumber(), result[1].toNumber()];
    items = items.sort(function(a, b)
    {
        return b[1] - a[1]
    });
}

Since this syntax is verbose, there are libraries (such as bluebird) to do this for you.

const getData = Promise.promisify(platform.getData)
for(let i = 0; i < total; i++)
{
    const result = await getData(i)
    items[i] = [result[0].toNumber(), result[1].toNumber()];
    items = items.sort(function(a, b)
    {
        return b[1] - a[1]
    });
}
0

I think the confusion is mostly around how JavaScript promises work (which is common!) YDKJS is a good resource. Another thing to note is that web3.js returns promises by default, so we don't need to "promisify" them.

I'd go about it like this:

  1. Get array size (platform.getArraySize)
  2. Create an array of promises (platform.getData) for each index position.
  3. Execute all of the promises in the array at the same time (and wait for all of them to complete)
  4. Sort the results
  5. Display the results

Code (untested):

 // 1. get length
 const total = await platform.getArraySize();

// 2. create array of promises. each promise will get the data, "then" format the results
const promiseArray = [];
for (let i = 0; i < total; i++) {
    promiseArray.push(
        platform.getData(i).then(result => {
            return [result[0].toNumber(), result[1].toNumber()];
        })
    );
}

// 3. execute all promises in parallel, return after *all* promises are complete
const items = await Promise.all(promiseArray);

// 4. sort
items = items.sort(function(a, b) {
    return b[1] - a[1];
});

// 5. add to DOM
for(let i = 0; i < items.length; i++)
{
    $("#container").append("<div>a: " + items[i][0] + ", b: " + items[i][1] + "</div>");
}

Not the answer you're looking for? Browse other questions tagged or ask your own question.