Core tools and utilities for the web3.js ecosystem, providing foundational layer functionality for blockchain interactions.
—
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.
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");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
});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);
}
}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");Batch processing provides significant performance improvements over individual requests:
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 requestsInstall with Tessl CLI
npx tessl i tessl/npm-web3-core