前言
有些时候,我们需要生成唯一 ID
看上去很简单的样子,但真要做到百分百不重复,可比想的要坑。
第一个坑:拿时间戳加随机数凑数
很多小伙伴的第一反应可能会这样来写
function backUniqueIDvalue() {
return Date.now().toString(36) + Math.random().toString(36).substr(2);
}
简单解释一下这段代码的意思
Date.now().toString(36)
Date.now():获取当前的时间戳(精确到毫秒的数字)。
toString(36):将这个时间戳数字转换为 36 进制的字符串。
36 进制包含 0-9 和 a-z(10数字+26个字母)。
这样可以让原本很长的数字时间戳变得非常短,且包含字母
简单解释一下这段代码的意思
Math.random().toString(36).substr(2)
Math.random():生成一个 0 到 1 之间的随机小数(例如 0.123456789)。
.toString(36):同样把这个小数转换为 36 进制字符串(例如 "0.4fzyo82mvyr")。
.substr(2):截取从第 2 位开始的字符串,目的是去掉开头的 "0.",只保留后面的随机字符部分。
举个例子:
如果当前时间戳转 36 进制是 "lxixn9",
随机数转 36 进制是 "0.abc123"
那么最终拼接的结果就是类似 "lxixn9abc123" 这样的一串短 ID
可能会出现的问题
看着好像是没有问题的,而且代码也挺简单的。
但是实际上放到生产环境中,这就是个定时炸弹
时间戳精度不够
Date.now()只能精确到毫秒,要是在同一毫秒里连续调用两次这个函数。
那么就会返回相同的结果,此时 ID 的前半段就会完全一样
我们都知道 Math.random()这玩意生成的不是真正的随机数,只是伪随机数。
运气不好的时候,在较短时间内可能跑出一模一样的序列
说到这里,小伙伴们可能已经知道,生成的 ID 唯一性可能不是那么高,可能会重复的。
第二个坑:用自增的计数器
还其他小伙伴想的更简单:整个全局的数字。
每次生成 ID 就把数字加 1,从 0 开始往上排不就得了?
但是如果用户开了俩同款页面,每个页面的计数器都是从零开始算,生成的 ID 会直接重复。
显然,这样的办法不太行。
这个时候,今天我们的主角就要闪亮登场了。
掌声有请:crypto.randomUUID()
下面我们简单介绍一下我们的专家大拿
crypto.randomUUID() 是 ES2023标准 API
crypto.randomUUID() 是 ES2023标准 API.
ES2023(即 ECMAScript 2023)是在 2023年 正式推出的。
crypto.randomUUID() 浏览器的版本要求
浏览器环境:Chrome 92+、Firefox 95+、Safari 15.4+。
该 API 只能在安全上下文(即 HTTPS 或 localhost)中使用(重要)。
判断浏览器是否支持 crypto.randomUUID()
判断是否支持crypto.randomUUID()。
使用 typeof 检查typeof是否是 undefined
然后使用 typeof 检查crypto.randomUUID是否是一个函数
如果都成立的话,说明支持
// 兼容性写法
let uniqueId;
if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
// 现代环境直接使用原生 API
uniqueId = crypto.randomUUID();
// 生成的是:96e74085-38de-46bf-ba25-f85fe1bafc9d 这种格式的字符串
} else {
// 旧环境降级方案(例如引入 uuid 第三方库)
// uniqueId = uuid.v4();
console.warn('当前环境不支持 crypto.randomUUID');
}
为啥说这个是王者呢?
即使你以每秒生成 10 亿 个 UUID 的速度,持续生成 100 年。
发生一次重复的概率依然低于 10⁻³⁶(即 1 后面跟着 36 个零)。
换句话说,你需要生成大约 2.71 万亿个id,才会有十亿分之一的概率发生一次重复。
小伙伴们是不是觉得很厉害呢?
crypto.randomUUID()需要注意的点
大家应该看到了这样一句话:
该 API 只能在安全上下文(即 HTTPS 或 localhost)中使用。
换一句话说:
本地开发时:使用 localhost 或 127.0.0.1 访问,它是可以正常工作的。
如果你的网页是通过普通的 http:// 协议
(例如 http://192.168.1.10 或 http://xxx.com)访问的
浏览器就会出于安全考虑,直接禁用这个 API。此时调用它。
控制台通常会报错 TypeError: crypto.randomUUID is not a function。
crypto.randomUUID()也是不想象中的那样强大
本来以为是瑶瑶领先同行的。结果还隐藏着安全上下文的限制
其他生成唯一 id 第三方库 uuid 库
安装:npm install uuid
使用:
import { v4 as uuidv4 } from 'uuid';
const id = uuidv4();
其他的办法生成唯一 id
我旁边机智的小伙伴说:这样写也可以
Math.random() + Math.random()+ Math.random()+ Math.random()
实在绷不住了,哈哈