如何生成一个不会重复随机数?

JavaScript性能优化实战 10w+人浏览 444人参与

在 JavaScript 中,不存在绝对“永远不会重复”的纯随机数,但可通过“随机因子+唯一标识”组合生成全局唯一标识符(UUID) 或有序唯一 ID,实现“实际应用中永不重复”,以下是 3 种主流方案:

1. 最通用:生成 UUID(推荐)


UUID(如 UUID v4)通过随机数算法生成 128 位唯一字符串,重复概率极低(可忽略不计),无需依赖外部库,浏览器和 Node.js 均支持。


浏览器环境(原生 API)
现代浏览器(Chrome 89+、Firefox 91+ 等)支持  crypto.randomUUID() ,安全性和效率更高:

javascript:
  
// 生成 UUID v4(格式:xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx)
const uniqueId = crypto.randomUUID();
console.log(uniqueId); // 示例:"a1b2c3d4-5678-49ab-cdef-1234567890ab"

兼容方案(含 Node.js)
若需兼容旧浏览器或在 Node.js 中使用,可自定义 UUID 生成函数:

javascript:
  
function generateUUID() {
  // 利用随机数和固定规则生成 UUID v4
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
    const r = Math.random() * 16 | 0;
    const v = c === 'x' ? r : (r & 0x3 | 0x8);
    return v.toString(16);
  });
}

// 使用
const uniqueId = generateUUID();
console.log(uniqueId); // 示例:"3e4f5a6b-7c8d-4e5f-8a9b-0c1d2e3f4a5b"

2. 简单组合:时间戳+随机数+设备标识
 
利用“高精度时间戳(确保时间唯一性)+ 随机数(增加随机性)+ 设备信息(避免多设备冲突)”拼接,适合轻量场景。

javascript:
  
function generateUniqueId() {
  // 1. 纳秒级时间戳(比毫秒更精确,避免同一毫秒重复)
  const timestamp = performance.now().toString().replace('.', ''); 
  // 2. 4位随机数
  const random = Math.floor(Math.random() * 10000).toString().padStart(4, '0');
  // 3. 设备标识(简化版:取浏览器用户代理的哈希值)
  const deviceHash = btoa(navigator.userAgent).slice(0, 6); 
  // 拼接生成唯一ID
  return `${timestamp}_${random}_${deviceHash}`;
}

// 使用
const uniqueId = generateUniqueId();
console.log(uniqueId); // 示例:"1234567890123_4567_aBcDef"

3. 分布式场景:雪花算法(Snowflake)
 
若需在多服务/多设备环境中生成有序且唯一的 ID(含随机因子),可实现雪花算法(64 位整数),结构如下:
 

  • 1 位符号位(固定 0,确保为正数);
  • 41 位时间戳(毫秒级,可使用约 69 年);
  • 10 位机器标识(如设备 ID 哈希,支持 1024 台设备);
  • 12 位序列号(每台设备每毫秒可生成 4096 个唯一 ID)。
JavaScript 实现示例:
  
class Snowflake {
  constructor(machineId = 1) {
    this.machineId = machineId & 0x3ff; // 机器ID限制为10位
    this.sequence = 0; // 序列号(0-4095)
    this.lastTimestamp = -1; // 上一次生成ID的时间戳
  }

  // 生成唯一ID
  nextId() {
    let timestamp = Date.now();
    // 处理时钟回拨(避免时间倒退导致重复)
    if (timestamp < this.lastTimestamp) throw new Error("时钟回拨,无法生成ID");
    
    // 同一毫秒内,递增序列号
    if (timestamp === this.lastTimestamp) {
      this.sequence = (this.sequence + 1) & 0xfff; // 限制为12位
      if (this.sequence === 0) timestamp = this.waitNextMs(); // 序列号用尽,等待下一毫秒
    } else {
      this.sequence = 0; // 新毫秒,重置序列号
    }

    this.lastTimestamp = timestamp;
    // 拼接64位ID:时间戳左移22位 + 机器ID左移12位 + 序列号
    return (
      ((timestamp - 1609459200000) << 22) | // 时间戳偏移(以2021-01-01为起点)
      (this.machineId << 12) | 
      this.sequence
    );
  }

  // 等待下一毫秒
  waitNextMs() {
    let timestamp = Date.now();
    while (timestamp <= this.lastTimestamp) timestamp = Date.now();
    return timestamp;
  }
}

// 使用(指定机器ID为1,多设备需分配不同ID)
const snowflake = new Snowflake(1);
const uniqueId = snowflake.nextId();
console.log(uniqueId); // 示例:1234567890123456789(64位整数)

总结
 日常场景:优先用  crypto.randomUUID() (浏览器)或自定义 UUID 函数,简单高效;
轻量场景:用“时间戳+随机数+设备标识”,无需复杂逻辑;
分布式/有序场景:用雪花算法,确保多设备无重复且 ID 有序。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值