Node.js执行Redis集合操作传入回调函数无日志输出问题
问题背景
使用Node.js操作Redis存储Set类型去重数据时,写入、读取操作的回调函数均未触发,控制台无日志输出。使用的操作代码如下:
client.sAdd('frameworks_set',['ReactJS', 'Angular', 'Svelte', 'VueJS', 'VueJS'],function(err, reply){ console.log("retieved"+ reply)}); client.sMembers('frameworks_set',function(err, reply){ console.log("retieved"+ reply) });
通过Redis原生命令行客户端验证,数据实际已成功写入,smembers frameworks_set返回结果正常:
127.0.0.1:6379> smembers frameworks_set 1) "Angular" 2) "Svelte" 3) "VueJS" 4) "ReactJS"
核心原因
回调未触发基本都是以下问题导致:
- 未监听Redis客户端的
error事件,连接阶段的报错会被静默吞掉,没有任何提示 - 未等待客户端连接就绪就直接执行命令,旧版客户端会把命令暂存在队列,如果连接最终失败,队列里的命令回调不会执行
- 新版redis@4.x客户端默认要求显式调用
connect()建立连接,未调用连接的情况下命令不会实际发送,回调也不会触发 - 代码未处理回调中的
err入参,就算命令执行报错也看不到日志
修复方案
根据你使用的redis客户端版本选择对应写法即可:
旧版(redis@3.x及以下)
必须先监听错误事件,等待连接就绪后再执行命令,同时注意异步命令的执行顺序,不要并行执行有依赖关系的操作:
const redis = require('redis'); const client = redis.createClient({ host: '127.0.0.1', port: 6379 }); // 必须加错误监听,否则连接异常无任何输出 client.on('error', (err) => { console.error('Redis连接/操作出错:', err); }); // 连接就绪后再执行业务操作 client.on('ready', () => { client.sAdd('frameworks_set', ['ReactJS', 'Angular', 'Svelte', 'VueJS', 'VueJS'], (err, addCount) => { if (err) return console.error('sAdd执行失败:', err); console.log('sAdd新增元素数量:', addCount); // 写入完成后再执行查询,避免查询到写入前的状态 client.sMembers('frameworks_set', (err, members) => { if (err) return console.error('sMembers执行失败:', err); console.log('集合查询结果:', members); // 操作完成后关闭连接,避免进程常驻 client.quit(); }); }); });
新版(redis@4.x及以上)
新版客户端默认支持Promise,必须显式调用connect()建立连接,推荐用async/await写法更简洁:
const redis = require('redis'); async function runSetOperation() { const client = redis.createClient({ url: 'redis://127.0.0.1:6379' }); client.on('error', (err) => console.error('Redis客户端错误:', err)); // 必须显式调用connect建立连接 await client.connect(); const addCount = await client.sAdd('frameworks_set', ['ReactJS', 'Angular', 'Svelte', 'VueJS', 'VueJS']); console.log('sAdd新增元素数量:', addCount); const members = await client.sMembers('frameworks_set'); console.log('集合所有成员:', members); await client.quit(); } runSetOperation();
注意:所有Redis操作都是异步IO,不要在调用写入命令后立刻并行调用读取命令,否则大概率会读到写入前的旧数据。
内容的提问来源于stack exchange,提问作者G lau
相关产品推荐
相关产品推荐

