Node.js中Express+Socket.io按序发送文件数据时的图片重复问题
问题根源与修复方案
核心问题分析
- 全局变量污染:
buffer、img、img_path未用let/const声明,属于全局作用域。多个send函数异步执行时,后一次调用会覆盖前一次的变量值,导致最终发送的都是最后一次的图片数据。 - 不可靠的异步等待:用
setTimeout(100ms)等待图片读取完全依赖时间预估,一旦文件读取耗时超过100ms,会发送空buffer;读取太快则可能被后续异步读取覆盖。 - forEach不支持异步等待:
files.forEach(async file => { ... })中的await不会阻塞循环,所有send函数几乎同时执行,加剧变量污染。 - 错误处理缺失:图片读取、JSON解析的错误未被捕获,也未正确reject Promise。
修复后的完整代码
const fs = require('fs').promises; const path = require('path'); async function send(file) { try { // 读取并解析JSON文件 const jsonString = await fs.readFile(path.join(dir, file), 'utf8'); const jsonData = JSON.parse(jsonString); let buffer = ""; let img = false; const imgBasePath = path.join(dir, jsonData.number); // 优先读取jpg,不存在再尝试png try { buffer = await fs.readFile(`${imgBasePath}.jpg`); img = true; } catch (err) { try { buffer = await fs.readFile(`${imgBasePath}.png`); img = true; } catch (err2) { // 两种图片都不存在时保持初始值 } } const data = { number: jsonData.number, image: img, buffer: buffer.toString('base64') }; socket.emit('data', data); console.log(`已发送文件: ${file}`); } catch (err) { console.error(`处理文件${file}出错:`, err); throw err; } } async function files() { try { const files = await fs.readdir(dir); // 用for...of确保逐个处理,等待前一个完成再执行下一个 for (const file of files) { if (path.extname(file) === '.json') { await send(file); } } } catch (err) { console.error('读取目录出错:', err); } } files();
关键修复点说明
- 使用
fs.promises:将回调式文件读取转为Promise风格,配合await精准等待异步操作完成,彻底抛弃不可靠的setTimeout。 - 变量作用域隔离:所有变量用
let/const声明在send函数内部,每次调用创建独立变量实例,避免被后续调用覆盖。 for...of替代forEach:for...of支持await,确保文件按顺序处理,不会并行触发send导致变量冲突。- 路径安全处理:用
path.join拼接路径,避免因操作系统路径分隔符差异引发错误。 - 完善错误捕获:每个异步操作包裹
try/catch,错误会被打印并向上抛出,便于排查问题。
内容的提问来源于stack exchange,提问作者PioterSky
相关产品推荐
相关产品推荐

