一行代码生成绝对唯一 ID?别再用 Date.now()
了!
在日常开发中,我们经常会遇到“生成唯一 ID”的需求:如元素标识、缓存键、表单提交标识、防止重复点击等。虽然这个需求听起来简单,但你真的生成了绝对不会重复的 ID 吗?
如果你还在用 Date.now()
或 Math.random()
来拼接 ID,那么你离“唯一”可能还差得很远。
🚫 误区一:Date.now()
+ Math.random()
= 唯一?
function generateNaiveId() {
return Date.now().toString(36) + Math.random().toString(36).substr(2);
}
// 示例输出: "l6n7f4v2am50k9m7o4"
这个方法看起来挺有道理:前半部分是当前时间戳,后半部分是随机字符串。实际情况却是:
- 时间戳精度有限:
Date.now()
的单位是毫秒,在同一毫秒内执行多次该函数,前缀是完全一样的。 - 伪随机不靠谱:
Math.random()
不是加密级别的随机,短时间内可能重复。 - 并发冲突隐患大:在高并发或循环生成 ID 的场景下,很容易出现重复 ID。
✅ 建议:这个方法仅适合低频操作或不那么重要的标识场景,在生产环境中请慎用!
🚫 误区二:自增计数器
let counter = 0;
function generateCounterId() {
return `id-${counter++}`;
}
更简单粗暴的方式是自增计数器,但它的问题更加致命:
- 页面刷新就重置:
counter
是内存变量,刷新页面或重开标签页就会从 0 重新开始。 - 无法跨标签页同步:每个标签页是独立环境,完全无法共享 counter。
- 前端无状态:除非将状态持久化存储(如 LocalStorage),否则无法保持唯一性。
❌ 本地自增 ID 在浏览器环境几乎没有实际价值,只适合临时调试。
✅ 解决之道:crypto.randomUUID()
浏览器早就为我们准备好了官方的唯一 ID 生成器!
const uniqueId = crypto.randomUUID();
console.log(uniqueId);
// 示例输出: "3a6c4b2a-4c26-4d0f-a4b7-3b1a2b3c4d5e"
这个方法来自于浏览器原生的 crypto
模块,生成的是符合 RFC 4122 v4 规范的 UUID。
它为什么是王者方案?
- 🔐 加密级随机性:使用 CSPRNG(加密安全伪随机数生成器),不是
Math.random()
那种“伪随机”。 - 🌍 全局唯一性:v4 UUID 的随机空间高达
2^122
,碰撞几乎不可能发生。 - 🧩 跨端标准化:后端语言(如 Java、Go、Python)也使用 UUID,通用性极强。
- 🧪 无需依赖:不需要引入
uuid
库,直接一行搞定! - ⚡ 性能优秀:比你自己写的函数快得多,还更安全。
✅ 浏览器/环境支持情况
环境 | 支持版本 |
---|---|
Chrome | 92+ |
Firefox | 90+ |
Safari | 15.4+ |
Node.js | 14.17+ |
对于大多数现代项目,crypto.randomUUID()
是既安全又可靠的选择。
✅ 降级方案(兼容旧浏览器)
如果你需要兼容旧浏览器,可以使用 polyfill 或使用成熟的库,如:
npm install uuid
import { v4 as uuidv4 } from 'uuid';
const id = uuidv4();
虽然多了一点依赖,但同样稳定靠谱。
🧠 总结
方案 | 是否唯一 | 安全性 | 适合场景 |
---|---|---|---|
Date.now() + Math.random() | ❌ | ❌ | 非核心逻辑 |
自增 ID | ❌ | ❌ | 调试或临时用途 |
crypto.randomUUID() | ✅ | ✅ | 生产级、高并发环境 |
uuid 第三方库 | ✅ | ✅ | 老项目/兼容环境 |
🚀 最后一句话
别再手搓 ID 了,用 crypto.randomUUID()
,一行代码,稳如老狗!
const id = crypto.randomUUID();
让我们从今天开始,拥抱现代标准,告别“伪唯一”。