Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is batch.execute() asynchronous? #3411

Closed
ilyador opened this issue Mar 10, 2020 · 7 comments
Closed

Is batch.execute() asynchronous? #3411

ilyador opened this issue Mar 10, 2020 · 7 comments
Labels
1.x 1.0 related issues

Comments

@ilyador
Copy link

ilyador commented Mar 10, 2020

I cannot figure out from the docs how to correctly use the data returned from the batch requests.

At first, I tried a naive implementation

async function getLatestBlocks (n) {
  const latest = await eth.getBlockNumber()
  const blockNumbers = getBlockNumbers(latest, n)
  const batch = new eth.BatchRequest()
  let blocks = []

  blockNumbers.forEach(blockNumber => {
    batch.add(
      eth.getBlock.request(blockNumber, (error, data) => {
        blocks.push(data)
      })
    )
  })

  batch.execute()
  return blocks
}

But blocks was returning empty.

I tried using execute() as a promise, but it is not (I got execute has no method "then").

Since I am using React, I tried to populate the state in the request callback, but in that case, I have no indication of when the batch call is actually finished.

async function getLatestBlocks (n) {
  const latest = await eth.getBlockNumber()
  const blockNumbers = getBlockNumbers(latest, n)
  const batch = new eth.BatchRequest()

  blockNumbers.forEach(blockNumber => {
    batch.add(
      eth.getBlock.request(blockNumber, (error, data) => {
        setBlocksInfo(blocksArray => ([...blocksArray, data]))
      })
    )
  })

  batch.execute()
  setLoading(false) // not in sync with batch.execute()
}

So how do I know when batch.execute() has finished executing all the callbacks?

@cgewecke
Copy link
Collaborator

@ilyador You can manage the promise yourself, for example

async function getLatestBlocks (n) {
  const latest = await eth.getBlockNumber()
  const blockNumbers = getBlockNumbers(latest, n)
  const batch = new eth.BatchRequest()

  const total = blockNumbers.length;
  let counter = 0;
  let blocks = [];

  await new Promise(function(resolve, reject){
    blockNumbers.forEach(blockNumber => {
      batch.add(
        eth.getBlock.request(blockNumber, (error, data) => {
          if (error) return reject(error);

          counter++;
          blocks.push(data);

          if (counter === total) resolve();
        })
      )
    });

    batch.execute()
  });

  return blocks
}

^^^ Haven't actually tried the above, may have syntax error or other problems

@cgewecke cgewecke added 1.x 1.0 related issues support labels Mar 10, 2020
@ilyador
Copy link
Author

ilyador commented Mar 10, 2020

@cgewecke thanx

This issue #1446 says it was already made into a promise, or am I confusing something?

@cgewecke
Copy link
Collaborator

@ilyador Yes, it looks like the change was made to what is now the 2.x branch in #2000. 1.x requires that you manage the async aspect yourself.

There are some nice solutions in #1446 for this though, thanks for linking to that.

@ilyador
Copy link
Author

ilyador commented Mar 10, 2020

Got it, thanx

@ilyador ilyador closed this as completed Mar 10, 2020
@cameronprestera
Copy link

cameronprestera commented Jun 22, 2022

@ilyador I am actually trying to implement this exact thing, when I give a callback function with the batch request add, I am getting undefined for the callback for some strange reason. Would you mine sharing how you were able to get each block from multiple batch requests?

@aymantaybi
Copy link

For anyone wondering how to make the batch.execute asynchronous and get an Array of responses instead of calling requests callbacks individually, here's a function :

const Jsonrpc = require('web3-core-requestmanager/src/jsonrpc');

var { errors } = require('web3-core-helpers');

function executeAsync(batch) {

    return new Promise((resolve, reject) => {

        var requests = batch.requests;

        batch.requestManager.sendBatch(requests, (err, results) => {

            results = results || [];

            var response = requests.map((request, index) => {

                return results[index] || {};

            }).map((result, index) => {

                if (result && result.error) {
                    return errors.ErrorResponse(result);
                }

                if (!Jsonrpc.isValidResponse(result)) {
                    return errors.InvalidResponse(result);
                }

                return requests[index].format ? requests[index].format(result.result) : result.result;

            });

            resolve(response);

        });
    })

}

To use it :

var batch = new web3.BatchRequest();

batch.add(web3.eth.getBlock.request("latest"));
  
var batchResponse = await executeAsync(batch);

console.log(batchResponse);

@alison84r
Copy link

I am getting following error
An error occurred: TypeError: web3.eth.getBlock.request is not a function

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
1.x 1.0 related issues
Projects
None yet
Development

No branches or pull requests

5 participants