Go Back
Reward article creator

0.17 ETH

$0.00

ETH ($0.00)
All contributions go towards the creator

metamask

Tutorials

Using async Promises and await with Web3.js

POSTED03/05/2018

Intro

From the MetaMask developer FAQ:
"Using synchronous calls is both a technical limitation and a user experience issue. They block the user's interface. So using them is a bad practice, anyway. Think of this API restriction as a gift to your users."
Setting up a Web3 function to work asynchronously was pretty easy to figure out for a single call; but what about making multiple calls through Web3, that all need to be asynchronous, but also have dependencies on one another? An example would be calculating the ERC-20 token balance of an Ethereum address. To do this, you need to know both the balance of tokens at the address, but also the decimals value for that token to convert to the right units. JavaScript Promises are the natural solution here. They allow you to track the status of an asynchronous function, and perform actions after your multiple dependencies all resolve.

Turning Web3.js functions into JavaScript Promises

You can make an asynchronous requests by adding an error first callback to the Web3.js functions:
web3.eth.getBalance(address, function (error, result) {
    if (!error) {
        console.log(result);
    } else {
        console.error(error);
    }
});
If we depend on multiple calls from the Ethereum blockchain to create a result, using JavaScript Promises is a good solution. They allow you to react to a success or a failure from an asynchronous function. Creating a promise from the error first callback function is pretty straightforward:
function getBalance (address) {
  return new Promise (function (resolve, reject) {
    web3.eth.getBalance(address, function (error, result) {
      if (error) {
        reject(error);
      } else {
        resolve(result);
    }
  })
}
But we can actually make this process even simpler for multiple Web3 functions by creating a wrapper which both makes the function asynchronous, and turn it into a promise; basically automating what we would repeat above for each different Web3 function we call. Here is the wrapper from 0xcaff posted in StackExchange:
const promisify = (inner) =>
    new Promise((resolve, reject) =>
        inner((err, res) => {
            if (err) {
                reject(err);
            } else {
                resolve(res);
            }
        })
    );
Now that we have a Promise, we can take advantage of the async/await pattern which simplifies not only the look, but also the behavior of Promises. Putting this all together, let's show how simple this makes getting the token balance for an ETH account. We convert our orginal "Hello World" getBalance into an ansychronous function, like so:
async function getBalance() {
    var address, wei, balance
    address = document.getElementById("address").value;
    wei = promisify(cb => web3.eth.getBalance(address, cb))
    try {
        balance = web3.fromWei(await wei, 'ether')
        document.getElementById("output").innerHTML = balance + " ETH";
    } catch (error) {
        document.getElementById("output").innerHTML = error;
    }
}
Not much shorter for a single function, but will certainly make things better the more separate functions we call. My next post will show the results of these smaller educational posts, and how we can put it together to create the project I have been hinting above: Getting the ERC-20 balance of an Ethereum Address. I hope this teaches you something! Again, this may be trivial to many, but was not so straightforward when I first started to tackling these problems. 

Outline

Intro
Turning Web3.js functions into JavaScript Promises
WRITTEN BYadmin