4

This might be more to do with my lack of understanding some JS basics however it's in ethereum/web3 context so here it goes.

I have a public array posts in my contract and a global variable in JS of the same name.

Using truffle/pudding framework on the frontend I am then trying to iterate through the array doing something like this:

length = 3;
posts = new Array(length);
for(i = 0; i < length; i++ ){
  social.posts.call(i).then(function(v){
    posts[i] = v;
  });
}

However by debugging I found out that the anonymous function gets executed only once and with i equal to 3. posts[3] gets set and nothing else. I must be doing something silly here. Please help.

Edit: So I understand now that the problem is because of the promises but is there another way to easily retrieve array values from the contract? Pudding was meant to help with this.

3

The problem is the result of using a Javascript Promise (provided by Pudding) that wraps the call. If you made the same call without a Promise wrapper it would work as you expect. But in your case the Promise is not resolving until you hit the end of the loop.

  • Are you saying that for this specific call I should drop Pudding and go with raw web3 call? That would require me to initialise the contract instance from scratch again using web3 etc. I though the idea of Pudding was to simplify those things. Also, it confused me because in the truffle doc here said that calls return immediately without any waiting. – md2312 May 2 '16 at 13:16
3

You can do:

var posts = [0,1,2,3].map(index => social.posts.call(index));

Promise.map(posts, post => {
  // Resolved Post Value
  console.log(post);
})
  • Promise.map isn't standard. Use: Promise.all(posts).then(posts => { ... }) – Raine Revere Apr 9 '17 at 17:13
2

never heard of truffle/ pudding framework. But my guess is this is a Closure problem.

the value of i in the anonymous function comes from the value of i outside of the anonymous function. There is a Closure object for each anonymous funtion that contains the variables the anonymous function uses where those variables are not globals and not locals. So i am guessing this code snippet is inside some other function. Lets call that other function A. When the value of the variable i changes inside function A then the values of ALL of the i variables in the closures change. Because the anonymous function execute after function A finishes executing they use the value of i = 3. One solution is to put an IFFE around anonymous function and pass in the value of i to the IFFE. Then the value of the i variable for each anonymous function would not change after the first time i was assigned a value in the anonymous function.

  • Hey, it works, although it gives me some warning about not exactly passing an anonymous function. Also, I though I get the idea of promises but in this case I'm not sure. The call is synchronous and should also return immediately according to the doc. Another thing is, you say that all of the i variables change but according to my debugging, the anonymous function would previously execute only once and not three times. I had put a console log there to log the value of i and would only see one '3' – md2312 May 2 '16 at 13:31
  • Actually, no. I didn't exactly get it right. I had {(function(v){ posts[i] = v; })(i)} at first but it's incorrect since the value of v doesn't get injected into the function now and i is passed as v. Therefore, is there even a way to do this with such closure? – md2312 May 2 '16 at 13:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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