Node.js与Redis Web应用异步Get方法疑问:是否需将函数放入回调?
问题解答
肯定要把get_recent_tweet的调用(包括启动定时任务的setInterval)放进redisClient.get()的回调里,原因很直白:
redisClient.get()是异步操作,它的回调要等Redis把数据返回后才会执行。要是你在回调外面直接开定时任务跑get_recent_tweet,那counts变量大概率还没拿到Redis里存的历史统计值,还是初始的0,这就会导致后续统计直接从0开始算,把之前存在Redis里的历史数据给覆盖掉,统计结果肯定错。
比如你原代码里,setInterval可能在Redis还没把tweet_counts读回来的时候就已经开始跑了,这时候counts还是0,完全没用到Redis里的正确初始值,等于白存了之前的统计。
调整后的代码示例
改完之后的代码大概是这样,确保先从Redis拿到初始计数,再启动定时任务:
const twitterClient = require('./init') let counts = 0; const tweet_array_IDs = []; const hashtag_search = "covid"; const pattern = "vaccine"; const redis = require("redis"); const redisClient = redis.createClient({ legacyMode: true, }); // 先连接Redis,成功后再处理初始化 redisClient.connect().then(() => { redisClient.get(pattern, function (err, tweet_counts) { if (err) { console.log("Redis读取错误: " + err); counts = 0; // 出错就从0开始 } else { // 有数据就转成数字,没有就设为0 counts = tweet_counts ? parseInt(tweet_counts, 10) : 0; } // 一切准备就绪,启动定时任务 setInterval(() => { get_recent_tweet(hashtag_search, pattern); }, 3000); }); }).catch(err => console.error('Redis连接失败:', err)); function get_recent_tweet(hashtag_search, pattern) { twitterClient.tweets.search({ q: '#' + hashtag_search, result_type: 'recent', }).then((response) => { const tweet_array = response.statuses; tweet_array.forEach(tweet => { // 用includes代替indexOf,更直观 if (!tweet_array_IDs.includes(tweet.id)) { tweet_array_IDs.push(tweet.id); if (tweet.text.includes(pattern)) { counts++; redisClient.incr(pattern); } } }); }).catch(err => console.error('推文搜索出错:', err)); } // 别在定时任务里导出,直接导出一个获取计数的方法,外部才能拿到最新值 module.exports = { getCurrentCount: () => counts };
额外提几个要注意的坑
tweet_array_IDs存在内存里,重启应用就没了,之前处理过的推文ID会丢失,导致重复统计老推文。建议把这些ID存到Redis的集合里,用SADD添加、SISMEMBER判断是否已处理,这样重启后也不会丢。- 原代码里把
module.exports = counts放在setInterval里完全没用,模块导出是一次性的,只会导出最开始的0值。要让外部能拿到最新计数,就得像上面那样导出一个函数。 - 要是觉得回调写法麻烦,可以关掉
legacyMode,用Redis的Promise API,配合async/await写代码,可读性会好很多。
内容的提问来源于stack exchange,提问作者S214ky
相关产品推荐
相关产品推荐

