Web3js

Web3.js 中多個依賴請求的最佳實踐

  • November 9, 2017

希望獲得一些關於使用 Web3.js 的非常常見場景的建議

假設您要計算乙太坊地址中存在的特定 ERC20 代幣合約的代幣數量。

為了準確地做到這一點,您需要通過 Web3.js 獲取balanceOf()decimals()值,然後調整餘額以給出最終值。

但是,這些 Web3 請求的最佳實踐是確保它們是非同步的,因此我們可能會在取回小數的不同時間取回餘額。

在返回這兩個值後顯示調整值的最佳方式是什麼?

根據我的簡短研究,您可以:

  • 使用 JavaScript 承諾
  • 使用 Web3.js 批處理
  • 嵌套非同步呼叫

還有其他選擇嗎?從上述選項中是否有最佳選擇?還是場景驅動?

謝謝卡洛姆的幫助。經過一番研究,感覺promise在這裡是正確的做法,也是未來web3.js預設採用的方法。為了解決我今天的問題,這就是我最終要做的事情:

我發現這條評論建議了一個簡單的包裝器,我可以將它添加到我的項目中並用以下方式包裝我的 Web3.js 函式:

const promisify = (inner) =>
   new Promise((resolve, reject) =>
       inner((err, res) => {
           if (err) {
               reject(err)
           } else {
               resolve(res);
           }
       })
   );

評論的作者然後提到用於await分配變數,但這對我不起作用。相反,我使用包裝器創建了一組Promise函式,並讓它們都觸發一個Promise.all.

因此,對於我文章中的具體範例,這就是我所做的:

tokenContract = web3.eth.contract(contractABI).at(contractAddress)

var dec = promisify(cb => tokenContract.decimals(cb))
var bal = promisify(cb => tokenContract.balanceOf(address, cb))
var tokName = promisify(cb => tokenContract.name(cb))
var tokSym = promisify(cb => tokenContract.symbol(cb))

Promise.all([dec, bal, tokName, tokSym]).then(function ([decimal, balance, tokenName, tokenSymbol]) {
   var adjustedBalance = balance / Math.pow(10, decimal)
   var output = adjustedBalance + " " + tokenSymbol + " (" + tokenName + ")";
   console.log(output)
})

輸出看起來像:

64.09856462716048 OMG (OMGToken)

我希望這對其他人也有幫助!

編輯:使外部函式非同步後,我能夠使這些await東西工作:

async function getERC20Balance() {
   var address, contractABI, contractAddress, tokenContract, balance, decimals, tokenName, tokenSymbol, adjustedBalance
   address = document.getElementById("address").value
   contractAddress = document.getElementById("contractAddress").value
   contractABI = human_standard_token_abi

   tokenContract = web3.eth.contract(contractABI).at(contractAddress)

   decimals = promisify(cb => tokenContract.decimals(cb))
   balance = promisify(cb => tokenContract.balanceOf(address, cb))
   tokenName = promisify(cb => tokenContract.name(cb))
   tokenSymbol = promisify(cb => tokenContract.symbol(cb))

   adjustedBalance = await balance / Math.pow(10, await decimals)

   document.getElementById("tokenBalance").innerHTML = adjustedBalance;
   document.getElementById("tokenInfo").innerHTML = " " + await tokenSymbol + " (" + await tokenName + ")";
}

正如你所提到的,我認為選擇是基於場景的。具體來說,您的請求有多複雜以及需要進行多少次非同步呼叫。

其他要考慮的事情是(1)您對替代方案的熟悉程度,(2)您在程式碼庫的其餘部分中用於非同步呼叫的內容 - 最好保持一致性,以及(3)您的團隊對該方法的熟悉程度。

我將在其中添加另一個您未包含在列表中的內容:

  • ES8 async/await(雖然我會保持這種風格:更簡單、更簡潔的 promises/chains 編碼方式)

在您的範例中,您只檢索了兩個變數,這非常簡單,因此您可能可以很好地使用回調/嵌套非同步呼叫。但是,您擁有的變數或非同步請求越多,這將很快開始變得混亂(“回調地獄”),更不用說解決整個鏈可能需要更長的時間,因為每個順序呼叫都會等到前一個呼叫解決直到啟動。

因此,一旦您有更多的非同步呼叫,您就可以從 Promise 中受益,因為 (1) 更簡潔的語法,以及 (2) 通過使用Promise.all.

引用自:https://ethereum.stackexchange.com/questions/29967