我正在使用Web3.js查询各种以太坊智能合约的价格。这是异步完成的,很多时候这些值不按顺序返回,这意味着它们会以错误的顺序被推送到新数组。我想将值推送到forEach循环内的新数组,以便我可以使用jQuery更新页面上的值。保持秩序的最佳方法是什么?
采取的步骤:
首先,我将所有合同按顺序拼接成一个数组。
var Contracts = [];
Contract.splice(0, 0, EthereumContract.at("0x2a50fb3396455717043ae5aa631d362c94fe13e1"));
Contract.splice(1, 0, EthereumContract.at("0x69ec0658ff334789c7f57edc3a2f28adef1c0ef3"));
Contract.splice(2, 0, EthereumContract.at("0x4d2bab147c32c75c8c9277182e64c69e14cb9f3c"));
Contract.splice(3, 0, EthereumContract.at("0xcd56f2c89128ad71cfd87b0fc78c9e26990b0f66"));
然后我创建一个新的数组'TheCurrentPrice',它应该收到每份合约的价格。
var TheCurrentPrice = [];
现在我按顺序遍历数组并将Price方法应用于数组中的契约。我将返回的结果推送到一个新数组中。不幸的是,它有时会无序响应并被错误地推入新阵列。
Contract.forEach(function (Contract) {
Contract.Price(function (error, result) {
TheCurrentPrice.push(result);
});
});
解决方案:
Alnitak给出了正确答案,但语法不正确,以防将来有人试图这样做。
function PricePromise(Contract) {
return new Promise((resolve, reject) => {
Contract.Price(function (error, result) {
if (error) {
reject(error);
console.log("Price Error");
} else {
resolve(result);
console.log("Price " + result);
}
});
});
};
Promise.all(Contract.map(PricePromise))
.then(function(Price) {
('#Product-Price-1').attr('data-price', Price[0] / 1000000000000000000);
/*This uses jQuery to update a custom data-* attribute in HTML5. Price[0] is of course the first entry in the array of prices retrieved with the promise.*/
...
});
我不太明白为什么resolve(result)允许我放弃Price方法的forEach循环,但是你不需要forEach,这是正确的语法。
答案 0 :(得分:1)
.forEach
方法包含一个索引,因此您可以使用它来填充TheCurrentPrice
:
Contracts.forEach(function (Contract, index) {
Contract.Price(function (error, result) {
TheCurrentPrice[index] = result;
});
});
但请注意,您仍然需要某种形式的同步来告诉您何时获得所有价格。
因此,更好的解决方案可能是将Price
的调用封装为"Promises",然后使用Promise.all()
等待所有这些调用解析。
function PricePromise(contract) {
return new Promise(function(resolve, reject) {
contract.Price(function(error, result) {
if (error) {
reject(error);
} else {
resolve(result);
}
});
});
}
[注意:诸如bluebird.js之类的承诺库包括自动" Promisify"与Web3.js Price
函数签名]
Promise.all(Contracts.map(PricePromise)).then(function(TheCurrentPrice) {
// continue processing here with the values
// now already populated in "TheCurrentPrice"
...
});
如果您最终使用bluebird.js,可以稍微进一步简化上述内容:
Promise.map(Contracts, PricePromise).then(function(TheCurrentPrice) {
...
});
其中Promise.map
函数(尽管它不是标准函数,但是由Bluebird添加的函数)包含的附加功能允许您限制将要放置的并发调用数。
答案 1 :(得分:0)
您可以使用Array.prototype.forEach(索引)的第二个参数:
var date = new Date();
var dateMoment = moment(date).format("YYYY-MM-DD hh:mm");
console.log(dateMoment);
答案 2 :(得分:0)
您可以尝试在forEach的回调中添加一个函数'index'参数,然后您可以将当前价格设置到正确的位置。
Contract.forEach(function (Contract, index) {
Contract.Price(function (error, result) {
TheCurrentPrice[index]=result;
});
});