Как я могу (эффективно) связать свое обещание, которое возвращает массив со значением, а не с обещаниями? - PullRequest
0 голосов
/ 07 января 2019

У меня есть цепочка обещаний, которая находит массив. Я хочу, чтобы массив возвращал некоторые результаты (где в будущем я могу установить его в переменную состояния). Однако я получаю только обещания. Мне интересно, что я здесь делаю не так.

На данный момент я записываю консоль элементов в моем массиве, чтобы увидеть, возвращает ли он значение, а не Promise.

addIPFSItem = () => {

    var finalItems = []
    var searchAddress = "0x9Cf0dc46F259542A966032c01DD30B8D1c310e05";

    const contract = require('truffle-contract')
    const simpleStorage = contract(SimpleStorageContract)
    simpleStorage.setProvider(this.state.web3.currentProvider)

this.state.web3.eth.getAccounts((error, accounts) => {
  simpleStorage.deployed().then((instance) => {
    this.simpleStorageInstance = instance

    return this.simpleStorageInstance.getLength(searchAddress);
  }).then((accountLength) => {

    var movieItems = []
    var i;
    var indexCounter = 0;
    //WITHIN THIS LOOP extend the chain to add to movies
    for (i = 0; i < accountLength; i++) {

      var p = this.simpleStorageInstance.getBook(searchAddress, i, { from: searchAddress }).then((hashVal) => {
        return hashVal;
      }).then((hashVal)=>{
          var ipfsPrefix = "https://ipfs.io/ipfs/";
          var ipfsURL = ipfsPrefix + hashVal;
          return ipfsURL
      })

      var k = this.simpleStorageInstance.getTitle(searchAddress, i, { from: searchAddress }).then((title) => {
        return title;
      })

      var l = this.simpleStorageInstance.getContents(searchAddress, i, { from: searchAddress }).then((contents) => {
        return contents;
      })

      movieItems.push({id: i, poster_src: p, title: k, overview: l})
      indexCounter++
      console.log('counter: ', i, p, k, l)
    }

    //return items
    return movieItems
  }).then((array) =>{

    var i
    for(i=0; i<array.length; i++){
      console.log('Array item: ', array[i])
    }

    return finalItems
  })
})
}

Я не знаю, нужно ли мне связывать var p, var k, var l при добавлении его в массив movieItems. Возможно, после нажатия на movieItems я могу попытаться получить каждое значение в массиве, поскольку я уже получил значения, верно?

Ответы [ 2 ]

0 голосов
/ 07 января 2019

Это потому, что значения переменных p, k и l являются Promises. И они всегда будут обещаниями, потому что это то, что this.simpleStorageInstance.getBook() и другие возвращают. Добавление .then() к ним не заставляет их синхронно представлять их значения, они все еще являются Обещаниями. Вам нужно грамотно составлять Обещания, чтобы обеспечить доступность требуемых значений в то время и в нужном месте. Я предлагаю вам больше прочитать о том, как они работают.

Простым решением может быть простое использование await. Он в основном приостанавливает выполнение до завершения асинхронного Promise и гарантирует, что p, k и l представляют значения, которые вы ожидаете от них. Документация MDN .

addIPFSItem = () => {
  var finalItems = []
  var searchAddress = "0x9Cf0dc46F259542A966032c01DD30B8D1c310e05";
  const contract = require('truffle-contract')
  const simpleStorage = contract(SimpleStorageContract)
  simpleStorage.setProvider(this.state.web3.currentProvider)

  this.state.web3.eth.getAccounts((error, accounts) => {
    simpleStorage.deployed().then((instance) => {
      this.simpleStorageInstance = instance

      return this.simpleStorageInstance.getLength(searchAddress);
    }).then((accountLength) => {

      var movieItems = []
      var i;
      var indexCounter = 0;
      //WITHIN THIS LOOP extend the chain to add to movies
      for (i = 0; i < accountLength; i++) {

        let p = await this.simpleStorageInstance.getBook(searchAddress, i, { from: searchAddress }).then((hashVal) => {
          return hashVal;
        }).then((hashVal) => {
          var ipfsPrefix = "https://ipfs.io/ipfs/";
          var ipfsURL = ipfsPrefix + hashVal;
          return ipfsURL
        });

        let k = await this.simpleStorageInstance.getTitle(searchAddress, i, { from: searchAddress });

        let l = await this.simpleStorageInstance.getContents(searchAddress, i, { from: searchAddress });

        movieItems.push({ id: i, poster_src: p, title: k, overview: l })
        indexCounter++
        console.log('counter: ', i, p, k, l)
      }

      //return items
      return movieItems
    }).then((array) => {

      var i
      for (i = 0; i < array.length; i++) {
        console.log('Array item: ', array[i])
      }

      return finalItems
    })
  })
}

P.S. Если вы используете const, вы должны использовать let вместо var. В принципе, нет никакой причины использовать var в ES6.

0 голосов
/ 07 января 2019

Вы пытаетесь обмануть обещания здесь!

Когда вы запускаете

var l = this.simpleStorageInstance.getContents(searchAddress, i, { from: searchAddress }).then((contents) => {
  console.log('Retrieved contents');
  return contents;
});
movieItems.push({id: i, poster_src: p, title: k, overview: l});
console.log('Pushed!')

движок javascript говорит: «Я вставлю это Обещание в l напрямую и продолжу до movieItems.push». Если вы запустите это, вы увидите журналы как

  • Выдвинутый!
  • Полученное содержимое

Нам еще многое предстоит узнать об обещаниях, поэтому я не могу объяснить все в этом посте. Быстрое решение на данный момент, при условии, что у вас есть среда или инструмент сборки, который его поддерживает, использует async/await. Таким образом, вы можете заставить javascript «просто ждать», пока ваши обещания не будут выполнены.

сначала вы меняете }).then((accountLength) => { до }).then(async (accountLength) => { который сообщает javascript, что вы собираетесь использовать await и работать с Promises внутри функции. Тогда вы можете вместо .then использовать await следующим образом:

// Here I use `await` instead of `.then` to make the promise return "normally"
var hashVal = await this.simpleStorageInstance.getBook(searchAddress, i, { from: searchAddress });
// I do the transformations you did inside `.then(() => { ... })` "just" after the function call
var ipfsPrefix = "https://ipfs.io/ipfs/";
var ipfsURL = ipfsPrefix + hashVal;
var p = ipfsURL;

// Again, using `await` instead of `.then`
var k = await this.simpleStorageInstance.getTitle(searchAddress, i, { from: searchAddress })

var l = await this.simpleStorageInstance.getContents(searchAddress, i, { from: searchAddress });

Это заставит вашу функцию на самом деле возвращать массив значений вместо массива с обещаниями внутри. Надеюсь это поможет! :)

...