CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-web3-core

Core tools and utilities for the web3.js ecosystem, providing foundational layer functionality for blockchain interactions.

Pending
Overview
Eval results
Files

batch-processing.mddocs/

Batch Request Processing

The Web3 batch request system enables efficient grouping of multiple JSON-RPC requests into single network calls, reducing latency and improving performance for applications that need to make multiple blockchain queries simultaneously.

Capabilities

Web3BatchRequest Class

Main class for creating and executing batched JSON-RPC requests with promise-based result handling.

/**
 * Manages batched JSON-RPC requests for improved efficiency and reduced network overhead
 */
class Web3BatchRequest {
  constructor(requestManager: Web3RequestManager);
  
  // Properties
  readonly requests: JsonRpcRequest[];
  
  // Batch management
  add<ResponseType = unknown>(
    request: JsonRpcOptionalRequest<unknown>
  ): Web3DeferredPromise<ResponseType>;
  
  execute(options?: {timeout?: number}): Promise<JsonRpcBatchResponse<unknown, unknown>>;
}

Usage Examples:

import { Web3BatchRequest, Web3RequestManager } from "web3-core";
import { EthExecutionAPI } from "web3-types";

// Create request manager and batch request
const requestManager = new Web3RequestManager<EthExecutionAPI>(
  "https://eth-mainnet.g.alchemy.com/v2/your-api-key"
);

const batch = new Web3BatchRequest(requestManager);

// Add requests to batch and get promise handles
const blockNumberPromise = batch.add<string>({
  method: "eth_blockNumber",
  params: []
});

const gasPricePromise = batch.add<string>({
  method: "eth_gasPrice", 
  params: []
});

const balancePromise = batch.add<string>({
  method: "eth_getBalance",
  params: ["0x742d35Cc6634C0532925a3b8D0d3", "latest"]
});

// Execute batch - all requests sent in one network call
const batchResults = await batch.execute();

// Access individual results through promises
const blockNumber = await blockNumberPromise;
const gasPrice = await gasPricePromise;
const balance = await balancePromise;

console.log("Block number:", parseInt(blockNumber, 16));
console.log("Gas price:", parseInt(gasPrice, 16), "wei");
console.log("Balance:", parseInt(balance, 16), "wei");

Batch Request Building

Methods for constructing batched requests with individual promise handles for results.

/**
 * Add a JSON-RPC request to the batch
 * @template ResponseType - Expected response data type
 * @param request - JSON-RPC request object (without id and jsonrpc fields)
 * @returns Promise that resolves to the specific request's response
 */
add<ResponseType = unknown>(
  request: JsonRpcOptionalRequest<unknown>
): Web3DeferredPromise<ResponseType>;

/**
 * Access the array of queued requests
 */
readonly requests: JsonRpcRequest[];

Usage Examples:

const batch = new Web3BatchRequest(requestManager);

// Add various types of requests
const calls = [
  batch.add<string>({ method: "eth_blockNumber", params: [] }),
  batch.add<string>({ method: "eth_gasPrice", params: [] }),
  batch.add<Block>({ 
    method: "eth_getBlockByNumber", 
    params: ["latest", true] 
  }),
  batch.add<string>({ 
    method: "eth_getBalance", 
    params: ["0x742d35Cc6634C0532925a3b8D0d3", "latest"] 
  }),
  batch.add<Transaction>({ 
    method: "eth_getTransactionByHash", 
    params: ["0x1234567890abcdef..."] 
  })
];

// Inspect batch before execution
console.log("Batch contains", batch.requests.length, "requests");
batch.requests.forEach((req, index) => {
  console.log(`Request ${index + 1}: ${req.method}`);
});

// Execute and handle results
await batch.execute();

// Process results individually
const [blockNumber, gasPrice, latestBlock, balance, transaction] = await Promise.all(calls);

console.log("Results:", {
  blockNumber: parseInt(blockNumber, 16),
  gasPrice: parseInt(gasPrice, 16),
  blockHash: latestBlock.hash,
  balance: parseInt(balance, 16),
  txValue: transaction.value
});

Batch Execution

Execute batched requests with configurable timeout and comprehensive error handling.

/**
 * Execute all queued requests in a single batch call
 * @param options - Execution options
 * @param options.timeout - Request timeout in milliseconds
 * @returns Promise resolving to batch response with all results
 */
execute(options?: {timeout?: number}): Promise<JsonRpcBatchResponse<unknown, unknown>>;

/**
 * Default batch request timeout constant
 */
const DEFAULT_BATCH_REQUEST_TIMEOUT: 1000;

Usage Examples:

// Execute with default timeout
const batchResponse = await batch.execute();

// Execute with custom timeout (30 seconds)
const longBatchResponse = await batch.execute({ timeout: 30000 });

// Handle batch response
batchResponse.forEach((response, index) => {
  if ('result' in response) {
    console.log(`Request ${index + 1} succeeded:`, response.result);
  } else if ('error' in response) {
    console.error(`Request ${index + 1} failed:`, response.error);
  }
});

// Error handling for batch execution
try {
  await batch.execute({ timeout: 5000 });
} catch (error) {
  if (error.name === 'TimeoutError') {
    console.error("Batch request timed out after 5 seconds");
  } else {
    console.error("Batch execution failed:", error.message);
  }
}

Advanced Batch Patterns

Common patterns and best practices for efficient batch request usage.

/**
 * Web3DeferredPromise type for individual batch request results
 * @template T - Response type
 */
type Web3DeferredPromise<T> = Promise<T>;

/**
 * JSON-RPC batch response type
 */
type JsonRpcBatchResponse<Result = unknown, Error = unknown> = Array<
  JsonRpcResponse<Result> | JsonRpcError<Error>
>;

/**
 * Optional request type (id and jsonrpc fields added automatically)
 */
type JsonRpcOptionalRequest<T> = {
  method: string;
  params?: T;
};

Usage Examples:

// Pattern: Batch multiple balance checks
async function getBatchedBalances(addresses: string[]): Promise<{[address: string]: string}> {
  const batch = new Web3BatchRequest(requestManager);
  
  const balancePromises = addresses.map(address => ({
    address,
    promise: batch.add<string>({
      method: "eth_getBalance",
      params: [address, "latest"]
    })
  }));
  
  await batch.execute();
  
  const balances: {[address: string]: string} = {};
  for (const { address, promise } of balancePromises) {
    try {
      balances[address] = await promise;
    } catch (error) {
      console.error(`Failed to get balance for ${address}:`, error);
      balances[address] = "0x0";
    }
  }
  
  return balances;
}

// Pattern: Batch block range queries
async function getBlockRange(startBlock: number, endBlock: number): Promise<Block[]> {
  const batch = new Web3BatchRequest(requestManager);
  
  const blockPromises = [];
  for (let i = startBlock; i <= endBlock; i++) {
    blockPromises.push({
      blockNumber: i,
      promise: batch.add<Block>({
        method: "eth_getBlockByNumber",
        params: [`0x${i.toString(16)}`, false]
      })
    });
  }
  
  await batch.execute({ timeout: 30000 }); // Longer timeout for many blocks
  
  const blocks: Block[] = [];
  for (const { blockNumber, promise } of blockPromises) {
    try {
      const block = await promise;
      blocks.push(block);
    } catch (error) {
      console.error(`Failed to get block ${blockNumber}:`, error);
    }
  }
  
  return blocks.sort((a, b) => parseInt(a.number, 16) - parseInt(b.number, 16));
}

// Pattern: Mixed request types with error handling
async function getDashboardData(userAddress: string) {
  const batch = new Web3BatchRequest(requestManager);
  
  const promises = {
    blockNumber: batch.add<string>({ method: "eth_blockNumber", params: [] }),
    gasPrice: batch.add<string>({ method: "eth_gasPrice", params: [] }),
    balance: batch.add<string>({ 
      method: "eth_getBalance", 
      params: [userAddress, "latest"] 
    }),
    transactionCount: batch.add<string>({ 
      method: "eth_getTransactionCount", 
      params: [userAddress, "latest"] 
    }),
    chainId: batch.add<string>({ method: "eth_chainId", params: [] })
  };
  
  await batch.execute();
  
  try {
    const [blockNumber, gasPrice, balance, txCount, chainId] = await Promise.all([
      promises.blockNumber,
      promises.gasPrice, 
      promises.balance,
      promises.transactionCount,
      promises.chainId
    ]);
    
    return {
      currentBlock: parseInt(blockNumber, 16),
      gasPrice: parseInt(gasPrice, 16),
      userBalance: balance,
      transactionCount: parseInt(txCount, 16),
      chainId: parseInt(chainId, 16)
    };
  } catch (error) {
    console.error("Some dashboard data requests failed:", error);
    throw error;
  }
}

// Usage
const addresses = ["0x742d35Cc6634C0532925a3b8D0d3", "0x8ba1f109551bD432803012645Hac136c"];
const balances = await getBatchedBalances(addresses);

const blocks = await getBlockRange(18000000, 18000010);

const dashboardData = await getDashboardData("0x742d35Cc6634C0532925a3b8D0d3");

Performance Benefits

Batch processing provides significant performance improvements over individual requests:

  • Reduced Network Latency: Multiple requests sent in one HTTP call
  • Lower Connection Overhead: Single TCP connection handles multiple requests
  • Server Efficiency: Blockchain nodes can optimize batch processing
  • Rate Limit Optimization: Batch counts as single request for rate limiting
  • Error Isolation: Individual request failures don't affect other requests in batch

Performance Comparison Example:

// ❌ Inefficient: Individual requests
async function getDataIndividually() {
  const start = Date.now();
  
  const blockNumber = await requestManager.send({ method: "eth_blockNumber", params: [] });
  const gasPrice = await requestManager.send({ method: "eth_gasPrice", params: [] });
  const balance = await requestManager.send({ 
    method: "eth_getBalance", 
    params: ["0x742d35Cc6634C0532925a3b8D0d3", "latest"] 
  });
  
  const end = Date.now();
  console.log(`Individual requests took: ${end - start}ms`);
  
  return { blockNumber, gasPrice, balance };
}

// ✅ Efficient: Batch requests
async function getDataBatched() {
  const start = Date.now();
  
  const batch = new Web3BatchRequest(requestManager);
  const blockNumberPromise = batch.add({ method: "eth_blockNumber", params: [] });
  const gasPricePromise = batch.add({ method: "eth_gasPrice", params: [] });
  const balancePromise = batch.add({ 
    method: "eth_getBalance", 
    params: ["0x742d35Cc6634C0532925a3b8D0d3", "latest"] 
  });
  
  await batch.execute();
  
  const [blockNumber, gasPrice, balance] = await Promise.all([
    blockNumberPromise,
    gasPricePromise,
    balancePromise
  ]);
  
  const end = Date.now();
  console.log(`Batch requests took: ${end - start}ms`);
  
  return { blockNumber, gasPrice, balance };
}

// Typical results: Batch is 60-80% faster than individual requests

Install with Tessl CLI

npx tessl i tessl/npm-web3-core

docs

batch-processing.md

configuration-management.md

context-management.md

event-system.md

index.md

provider-integration.md

request-management.md

subscription-management.md

tile.json