Web3.eth订阅区块链实时事件时获取区块时间戳的高效替代方案
优化Web3事件订阅中获取区块时间戳的方法
1. 缓存区块时间戳,避免重复请求
每次事件触发就调用getBlock会重复请求相同区块的数据,拖慢速度。可以用一个Map缓存已获取的区块时间戳,后续同区块的事件直接用缓存值,还能定期清理缓存避免内存浪费。
代码示例:
// 缓存已查询的区块时间戳 const blockTimestampCache = new Map(); async function getTimestamp(blockNumber) { if (blockTimestampCache.has(blockNumber)) { return blockTimestampCache.get(blockNumber); } const block = await web3.eth.getBlock(blockNumber); const timestamp = block.timestamp; blockTimestampCache.set(blockNumber, timestamp); // 1小时后清理该缓存,可根据需求调整 setTimeout(() => blockTimestampCache.delete(blockNumber), 3600000); return timestamp; } // 订阅事件时调用 yourEventSubscription.on('data', async (result) => { const timestamp = await getTimestamp(result.blockNumber); // 这里处理时间戳逻辑 });
2. 预加载新区块时间戳
提前订阅newBlockHeaders事件,把每个新区块的时间戳先缓存起来。当你的业务事件触发时,对应的区块大概率已经在缓存里了,直接拿就几乎没延迟;如果是旧区块再兜底请求。
代码示例:
const latestBlockTimestamps = new Map(); // 订阅新区块,预存时间戳 web3.eth.subscribe('newBlockHeaders', (error, blockHeader) => { if (!error) { latestBlockTimestamps.set(blockHeader.number, blockHeader.timestamp); // 只保留最近100个区块的缓存,防止内存溢出 if (latestBlockTimestamps.size > 100) { const oldestBlockNum = Math.min(...latestBlockTimestamps.keys()); latestBlockTimestamps.delete(oldestBlockNum); } } }); // 处理业务事件 yourEventSubscription.on('data', (result) => { let timestamp = latestBlockTimestamps.get(result.blockNumber); if (!timestamp) { // 缓存里没有就请求区块,并存入缓存 web3.eth.getBlock(result.blockNumber).then(block => { timestamp = block.timestamp; latestBlockTimestamps.set(result.blockNumber, timestamp); // 处理时间戳 }); } else { // 直接用缓存的时间戳,无延迟 // 处理时间戳 } });
3. 让合约事件直接返回时间戳(适用于自定义合约)
如果是你自己开发的合约,触发事件时直接把block.timestamp作为参数emit出去,这样订阅事件时不用额外请求区块,直接从返回值里拿时间戳,这是最快的方法。
Solidity合约示例:
pragma solidity ^0.8.0; contract MyContract { // 事件里加入timestamp参数 event MyEvent(address indexed sender, uint256 value, uint256 timestamp); function doSomething(uint256 value) external { emit MyEvent(msg.sender, value, block.timestamp); } }
Web3处理代码:
yourEventSubscription.on('data', (result) => { // 直接从事件返回值取时间戳 const timestamp = result.returnValues.timestamp; // 处理时间戳逻辑 });
内容的提问来源于stack exchange,提问作者Aanchal Bhatti
相关产品推荐
相关产品推荐

