0

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?

3

2 Answers 2

4

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) 
});
Sign up to request clarification or add additional context in comments.

Comments

1

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()

7 Comments

"code here updating theData and then resolving" - no no no. Call ipfsRetrieve and use then, don't use new Promise
I think it's pretty clear what the OP wanted to achieve with ipfsRetrieve( hash ).then(function(data){ dataArray.push(data); }). When using Promise.all properly, you don't need any "data updating" at all.
Someone is going to want the data when the promises all resolve.
Yes, and that's what Promise.all does for you
Yes that's true, Promise.all returns an array of the resolved values.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.