Перебор массива в JS и простые промисы (web3/pudding)

Это может быть больше связано с моим непониманием некоторых основ JS, однако это в контексте ethereum/web3, так что вот оно.

У меня есть записи публичного массива в моем контракте и глобальная переменная в JS с тем же именем.

Используя структуру трюфеля/пудинга во внешнем интерфейсе, я затем пытаюсь выполнить итерацию по массиву, делая что-то вроде этого:

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

Однако путем отладки я обнаружил, что анонимная функция выполняется только один раз и при i равном 3 . posts[3] устанавливается и больше ничего. Должно быть, я делаю что-то глупое здесь. Пожалуйста помоги.

Изменить: теперь я понимаю, что проблема связана с обещаниями, но есть ли другой способ легко получить значения массива из контракта? Пудинг должен был помочь в этом.

Ответы (3)

Проблема является результатом использования обещания Javascript (предоставленного Pudding), которое оборачивает вызов. Если вы сделаете тот же вызов без оболочки Promise, он будет работать так, как вы ожидаете. Но в вашем случае Обещание не разрешается, пока вы не дойдете до конца цикла.

Вы говорите, что для этого конкретного вызова я должен отказаться от Pudding и перейти к необработанному вызову web3? Это потребовало бы, чтобы я снова инициализировал экземпляр контракта с нуля, используя web3 и т. д. Я думал, что идея Pudding заключалась в том, чтобы упростить эти вещи. Кроме того, это смутило меня, потому что в документе по трюфелю здесь сказано, что вызовы возвращаются немедленно, без ожидания.

Ты можешь сделать:

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

Promise.map(posts, post => {
  // Resolved Post Value
  console.log(post);
})
Promise.map не является стандартным. Использовать:Promise.all(posts).then(posts => { ... })

никогда не слышал о структуре трюфель/пудинг. Но я предполагаю, что это проблема закрытия.

значение i в анонимной функции происходит от значения i вне анонимной функции. Для каждой анонимной функции существует объект Closure, который содержит переменные, используемые анонимной функцией, где эти переменные не являются глобальными и не локальными. Итак, я предполагаю, что этот фрагмент кода находится внутри какой-то другой функции. Давайте вызовем эту другую функцию A. Когда значение переменной i изменяется внутри функции A, тогда изменяются значения ВСЕХ переменных i в замыканиях. Поскольку анонимная функция выполняется после завершения выполнения функции A, они используют значение i = 3. Одно из решений состоит в том, чтобы поместить IFFE вокруг анонимной функции и передать значение i в IFFE. Тогда значение переменной i для каждой анонимной функции не изменится после первого присвоения значения i в анонимной функции.

Эй, это работает, хотя и дает мне некоторое предупреждение о том, что не совсем передается анонимная функция. Кроме того, я понимаю идею обещаний, но в этом случае я не уверен. Вызов является синхронным и также должен немедленно возвращаться в соответствии с документом . Другое дело, вы говорите, что все переменные i изменяются, но согласно моей отладке анонимная функция раньше выполнялась только один раз, а не три раза. Я поместил туда журнал консоли, чтобы записать значение i, и увидел только одну цифру «3».
Вообще-то, нет. Я не совсем правильно понял. Сначала у меня было, {(function(v){ posts[i] = v; })(i)}но это неверно, поскольку значение v теперь не вводится в функцию, а i передается как v. Следовательно, есть ли способ сделать это с таким закрытием?