we.are
we.are

Reputation: 427

Calling async function inside a loop

I have the following function:

function ipfsRetrieve( ipfsHash ){
  return new Promise( function( resolve, reject ) {
    ipfs.catJSON( ipfsHash, (err, result) => {
        if (err){                
            reject(err);
        }
        resolve( result);           
    });
});    

}

Now, when I call this function inside a loop as below:

var hashArray   = [ "QmTgsbm...nqswTvS7Db",
                "QmR6Eum...uZuUckegjt",
                "QmdG1F8...znnuNJDAsd6",                    
              ]

var dataArray   = []; 
hashArry.forEach(function(hash){
    ipfsRetrieve( hash ).then(function(data){
        dataArray.push(data);
    });
});  

return dataArray

The "return dataArray' line returns an empty array. How should I change this code to have the "dataArray" filled with the data retrived from IPFS?

Upvotes: 0

Views: 1172

Answers (2)

Luca Kiebel
Luca Kiebel

Reputation: 10096

You should use Promise.all.

Construct an Array of Promises and then use the method to wait for all promises to fulfill, after that you can use the array in the correct order:

let hashArray = ["QmTgsbm...nqswTvS7Db",
  "QmR6Eum...uZuUckegjt",
  "QmdG1F8...znnuNJDAsd6",
]

// construct Array of promises
let hashes = hashArray.map(hash => ipfsRetrieve(hash));

Promise.all(hashes).then(dataArray => {
  // work with the data
  console.log(dataArray) 
});

Upvotes: 4

Steven Spungin
Steven Spungin

Reputation: 29071

For starters, you need to return after rejecting, or else your resolve will get called too.

function ipfsRetrieve( ipfsHash ){
  return new Promise( function( resolve, reject ) {
    ipfs.catJSON( ipfsHash, (err, result) => {
        if (err){                
           reject(err);
           return;
        }
        resolve( result);           
    });
});   

Now for the loop, use map instead of forEach, and return the promise. Then wait on the promises.

let promises = hashArry.map(hash=> return new Promise(resolve,reject) { // your code here handling hash, updating theData, and then resolving })
return Promise.all(promises).then( ()=> return theData)

In your case, the promise is provided by ipfsRetrieve, so you would call

let promises = hashArry.map(ipfsRetrieve)
return Promise.all(promises)

The caller of your functions will do this:

ipfsRetrieve().then(data=>{ // process data here } )

If you are cool with async await, do this. (marking containing function as async)

let data = await ipfsRetrieve()

Upvotes: 1

Related Questions