我如何(有效地)链接我的诺言,使诺言返回带有值而不是承诺的数组?

时间:2019-01-07 18:28:19

标签: javascript promise es6-promise

我有一个诺言链,可以找到一个数组。我希望数组返回一些结果(将来可以在其中将其设置为状态变量)。但是,我只是兑现诺言。我想知道我在这里做错了什么。

现在,我正在控制台记录阵列中的项目,以查看其是否返回值,而不是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 pvar kvar l添加到movieItems数组时是否需要链接它们。假设在我推到movieItems之后,我可以尝试获取数组中的每个值,因为我已经正确检索了这些值?

2 个答案:

答案 0 :(得分:2)

您正试图在这里欺骗诺言!

运行时

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 });

这将使您的函数实际上返回一个值数组,而不是内部带有promise的数组。 希望这可以帮助! :)

答案 1 :(得分:0)

这是因为变量pkl的值是 。他们将永远是诺言,因为这就是this.simpleStorageInstance.getBook()等人的回报。向它们添加.then()并不能使它们同步表示其值,它们仍然是Promises。您需要巧妙地编写Promises,以确保所需的值在您想要的时间和地点可用-我建议您更多地阅读它们的工作原理。

一个简单的解决方法可能是简单地使用await。它基本上会暂停执行,直到异步Promise完成为止,并将确保pkl代表您期望的值。 MDN documentation

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。基本上没有理由在ES6中使用var