
本文详解如何在 node.js 环境下正确读取本地 json 文件、获取其中数组长度,并基于此生成连续递增的整数 id(如 1, 2, 3…),同时规避异步回调、重复解析、竞态条件等常见陷阱。
本文详解如何在 node.js 环境下正确读取本地 json 文件、获取其中数组长度,并基于此生成连续递增的整数 id(如 1, 2, 3…),同时规避异步回调、重复解析、竞态条件等常见陷阱。
在构建轻量级服务(如原型或本地“伪数据库”)时,开发者常将数据以数组形式存于 xyz.json 文件中,并希望为每个新对象分配严格递增的数字 ID(如 id: 1, id: 2)。但直接在回调中 return 值(如原代码中的 return xyz.length + 1)无法生效——因为 fs.readFile 是异步操作,外层函数 idNo() 实际返回 undefined,导致后续 parseInt(idNo++) 报错或逻辑失效。
✅ 正确做法:使用 Promise 封装 + await 顺序执行
首先,将文件读写封装为 Promise 版本,避免嵌套回调:
将一个或多个视频上传至YouTube。当用户想“上传到YouTube”“发YouTube”“批量上传”“upload to YouTube”“post videos to YouTube”或发布到YouTube时使用此技能。
const fs = require('fs').promises;
// 安全读取 JSON 数组并返回其长度(若文件为空或非数组则默认为 0)
async function getArrayLength(filePath) {
try {
const data = await fs.readFile(filePath, 'utf-8');
const parsed = JSON.parse(data);
return Array.isArray(parsed) ? parsed.length : 0;
} catch (err) {
if (err.code === 'ENOENT') {
// 文件不存在 → 视为初始空数组
return 0;
}
if (err instanceof SyntaxError) {
throw new Error(`JSON 格式错误:${err.message}`);
}
throw err;
}
}
// 安全追加新对象并写回文件(含原子性保障)
async function appendWithAutoId(filePath, newItem) {
const currentLength = await getArrayLength(filePath);
const newItemWithId = {
id: currentLength + 1,
...newItem
};
try {
const existingData = await fs.readFile(filePath, 'utf-8');
const todos = JSON.parse(existingData);
if (!Array.isArray(todos)) throw new Error('JSON 根节点必须是数组');
todos.push(newItemWithId);
await fs.writeFile(filePath, JSON.stringify(todos, null, 2));
return newItemWithId;
} catch (err) {
if (err.code === 'ENOENT') {
// 文件不存在 → 创建新数组
await fs.writeFile(filePath, JSON.stringify([newItemWithId], null, 2));
return newItemWithId;
}
throw err;
}
}
✅ 使用示例(Express 路由中)
app.post('/todos', async (req, res) => {
try {
const newTodo = {
title: req.body.title,
description: req.body.description
};
const saved = await appendWithAutoId('xyz.json', newTodo);
res.status(201).json(saved);
} catch (err) {
console.error(err);
res.status(500).json({ error: err.message });
}
});
⚠️ 关键注意事项
- 不要重复 JSON.parse():原代码中多次调用 JSON.parse(data) 不仅低效,还易因异常中断流程;应解析一次后复用。
- 避免竞态条件:若多个请求并发写入,上述方案仍可能冲突(如两个请求同时读到长度 5,都生成 id: 6)。生产环境需引入文件锁(如 proper-lockfile)或改用 SQLite 等轻量数据库。
- ID 语义明确:此处 id 是插入序号(1-based),非时间戳或 UUID;若需全局唯一或分布式兼容,请切换为 crypto.randomUUID() 或 nanoid。
- JSON 写入格式化:使用 JSON.stringify(data, null, 2) 提高可读性与 diff 友好性,便于调试。
通过 Promise 化 I/O 操作、集中错误处理、幂等初始化逻辑,即可稳健实现“JSON 文件即数据库”的 ID 自增需求——简洁、可靠,且符合 Node.js 异步编程最佳实践。










