Web3监听智能合约事件问题:页面重载后重复输出事件日志
问题解答
这其实是watch()方法的默认行为导致的,并非事件持久化的预期表现,也不算你的使用方式完全错误——只是没考虑到它的默认扫描范围而已。
为什么刷新页面会重复输出?
web3.js的watch()方法,如果不指定fromBlock参数,默认会从区块链的第一个区块开始扫描所有匹配的Something事件。每次页面刷新后,你重新初始化了事件监听,它就会把历史上所有触发过的该事件再重新推送给回调函数,所以你会看到重复的日志输出。
怎么解决这个问题?
有两种常见的处理方式,根据你的需求选择:
1. 只监听刷新页面后的新事件
如果只关心页面加载之后触发的新事件,监听时指定fromBlock为'latest'(当前最新区块)即可:
var somethingEvent = contractInstance.Something({fromBlock: 'latest'}); somethingEvent.watch(function(error, result) { if (!error) { console.log(result.args.message); } });
这样只会监听从页面加载时的最新区块开始,后续新产生的Something事件,不会重复输出历史日志。
2. 保留历史事件但避免重复输出
如果你需要加载历史事件,但不想每次刷新都重复输出,可以本地存储最后处理过的区块编号,下次监听时从这个区块的下一个位置开始:
// 从本地存储获取上次处理到的区块号,默认用当前最新区块 const lastHandledBlock = localStorage.getItem('lastEventBlock') || 'latest'; var somethingEvent = contractInstance.Something({fromBlock: lastHandledBlock}); somethingEvent.watch(function(error, result) { if (!error) { console.log(result.args.message); // 更新本地存储的区块号,下次刷新就从这里开始 localStorage.setItem('lastEventBlock', result.blockNumber); } });
额外提示
如果你只是想一次性获取所有历史事件,不需要持续监听新事件,建议使用get()方法替代watch(),它只会获取指定区块范围内的事件,不会持续监听:
contractInstance.Something({fromBlock: 0, toBlock: 'latest'}, function(error, results) { if (!error) { results.forEach(result => { console.log(result.args.message); }); } });
内容的提问来源于stack exchange,提问作者totalnoob
相关产品推荐
相关产品推荐

