我們總會遇到需要生成“唯一ID”的場景,“唯一ID”這個需求看似簡單,但要實現(xiàn)一個絕對不會重復的 ID,卻比想象中要復雜。
誤區(qū)一:嘗試 (Date.now()
+ Math.random()
)
很多初學者(甚至一些老手)的直覺反應是:時間戳 + 隨機數(shù)。
function generateNaiveId() {
return Date.now().toString(36) + Math.random().toString(36).substr(2);
}
// 示例輸出: "l6n7f4v2am50k9m7o4"
這個方法看起來不錯,結合了時間的唯一性和隨機性。但在高并發(fā)或快速操作的場景下,它的“絕對唯一”承諾不堪一擊:
- 時間戳精度問題:
Date.now()
的精度是毫秒,如果在同一毫秒內調用兩次 generateNaiveId()
,ID 的前半部分就會完全一樣 - 偽隨機性:
Math.random()
產生的不是真正的“加密級”隨機數(shù),在極小的概率下,它也可能在短時間內生成重復的序列
結論: 這種方法在低頻次場景下“似乎”可用,但它離“絕對唯一”相去甚遠,是生產環(huán)境中的一顆定時炸彈。
誤區(qū)二:簡單的自增計數(shù)器
另一個思路是維護一個全局計數(shù)器。
這個方案的缺陷更加明顯:
- 無狀態(tài)性:瀏覽器環(huán)境是無狀態(tài)的,用戶一刷新頁面,
counter
就重置為 0 - 多標簽頁沖突:用戶打開兩個相同的頁面,每個頁面都有一個獨立的
counter
,它們會從 0 開始生成完全相同的 ID 序列,導致立刻沖突
結論: 純粹的自增計數(shù)器方案,在瀏覽器環(huán)境中幾乎沒有任何實用價值。
擁抱密碼學和標準
既然簡單的方法都行不通,我們需要更可靠、更科學的武器。幸運的是,瀏覽器(Node.js14+)已經為我們內置了這樣的武器。
王者方案:crypto.randomUUID()
這是 W3C 標準和現(xiàn)代瀏覽器提供的官方解決方案。crypto
是一個瀏覽器內置的全局對象,提供了加密相關的能力,而 randomUUID()
方法專門用于生成一個符合 RFC 4122 v4 規(guī)范的通用唯一標識符(UUID)。
const uniqueId = crypto.randomUUID();
// 示例輸出: "3a6c4b2a-4c26-4d0f-a4b7-3b1a2b3c4d5e"
為什么 crypto.randomUUID()
是王者?
- 極低的碰撞概率:一個 v4 UUID 是由 122 位的隨機數(shù)生成的,其組合數(shù)量是一個天文數(shù)字,碰撞概率趨近于零
- 加密級安全:它使用密碼學安全偽隨機數(shù)生成器(CSPRNG),其隨機性遠非
Math.random()
可比,無法被預測 - 標準化:它生成的是全球公認的標準格式,無論前端、后端還是數(shù)據(jù)庫,都能識別和處理
- 原生、簡單、高效:無需引入任何第三方庫,一行代碼即可調用,性能極高
crypto.randomUUID()
已經得到了所有現(xiàn)代主流瀏覽器的支持(Chrome 92+, Firefox 90+, Safari 15.4+, Node.js14+)。對于絕大多數(shù)新項目而言,可以放心使用。
該文章在 2025/7/14 16:19:18 編輯過