Web3.js – Are Contract Calls Asynchronous?

contract-designcontract-developmentweb3js

Suppose we have a contract:

contract C {

    uint256 a;
    uint256 b;

    function setA(uint256 aval) {
        a = aval;
    }

    function setB(uint256 bval) {
        b = bval;
    }

    function getA() constant returns (uint256) { 
        return a;
    }

    function getB() constant returns (uint256) {
        return b;
    }
}

and we try to set values, get them and store them into an array using web3.js:

var ABI = [{"constant":false,"inputs":[{"name":"bval","type":"uint256"}],"name":"setB","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"getB","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":true,"inputs":[],"name":"getA","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"aval","type":"uint256"}],"name":"setA","outputs":[],"type":"function"}];
var contractAddress = "0x11111222222222222222";
var contract = web3.eth.contract(contractAddress, ABI);
var numbers = [];

// Set the values
contract.call().setA(100);
contract.call().setB(200);

// Get them and add them to the array
var a = contract.call().getA();
numbers.push(a);
var b = contract.call().getB();
numbers.push(b);

Can b be added to the array before a? I know that web is asynchronous for most methods but does this apply to contract method invocation as well?

Best Answer

There are both synchronous and asynchronous versions of:

myContractInstance.myMethod.call(param1 [, param2, ...] [, transactionObject] [, defaultBlock] [, callback]);

as documented in https://github.com/ethereum/wiki/wiki/JavaScript-API#contract-methods

Using the synchronous version:

var a = contract.getA.call();
numbers.push(a);
var b = contract.getB.call();
numbers.push(b);

b will always be in the array after a.


To use the asynchronous version, you pass a callback, like:

var a = contract.getA.call(function(error, value) {
});

The order of the array will depend on what's done in the callback/s.


Note that sendTransaction should be used for setting the values and this won't work:

// Set the values
contract.call().setA(100);
contract.call().setB(200);

You need to use:

contract.setA.sendTransaction(100, callback); and all the other code needs to be inside the callback, because sendTransaction is only asynchronous. Furthermore, the callback of sendTransaction will only return a transaction hash and you need to poll until getTransactionReceipt is not null to know that the transaction has been mined and the value of a has been set.