在服務端使用 64 位長整型(Int64)數(shù)字,而前端通過 JavaScript 的number
類型接收時,若數(shù)值超過2^53 - 1
(即 9007199254740991),會出現(xiàn)數(shù)值不相等的問題。這一現(xiàn)象的核心原因是 JavaScript 中number
類型的精度限制,而雪花算法生成的 ID(通常為 64 位)恰好屬于這類場景,因此需要特別處理。
一、問題根源:JavaScript 中number的精度限制
JavaScript 的number
類型基于IEEE 754 雙精度浮點數(shù)標準實現(xiàn),其底層存儲結構決定了它的精度范圍:
雙精度浮點數(shù)的 “尾數(shù)(mantissa)” 部分占 52 位,加上隱藏的 1 位 “整數(shù)位”,總共可表示53 位有效精度。
這意味著:對于整數(shù),number
類型能精確表示的范圍是[-2^53 + 1, 2^53 - 1]
,這個范圍外的整數(shù)無法被精確存儲,會出現(xiàn) “精度丟失”。
當服務端返回的 Int64 數(shù)值超過2^53 - 1
時,JavaScript 的number
會因無法精確表示該值,導致存儲的結果與實際值不一致(例如末尾幾位被截斷或四舍五入)。
二、典型場景:雪花算法 ID 的問題
雪花算法(Snowflake)生成的 ID 是 64 位整數(shù),結構通常為:
1 位符號位(固定為 0,保證正數(shù));
41 位時間戳;
10 位機器 ID;
12 位序列號。
顯然,64 位整數(shù)的最大值為2^63 - 1
(約 9e18),遠超過2^53 - 1
,因此用number
接收時必然會丟失精度,導致前端存儲的 ID 與服務端實際值不匹配(例如服務端 ID 為1234567890123456789
,前端接收后可能變成1234567890123456700
)。
三、解決方法:如何避免精度丟失?
解決的核心思路是繞開 JavaScriptnumber
類型的精度限制,常見方案如下:
1. 以字符串形式傳遞大整數(shù)
最直接的方式是服務端在返回數(shù)據(jù)時,將 Int64 類型的字段轉換為字符串,前端接收后以字符串形式存儲和使用。
- 服務端處理:例如在 Java 中,將
Long
類型的雪花 ID 轉換為String
后再序列化到 JSON 中; - 前端接收:直接使用字符串類型的 ID(無需轉換為
number
),避免精度丟失。
2. 前端使用BigInt類型處理大整數(shù)
BigInt
是 JavaScript 中專門用于表示任意精度整數(shù)的類型,可精確存儲超過2^53 - 1
的數(shù)值。
- 服務端:保持 Int64 類型的數(shù)值(例如 JSON 中直接存儲數(shù)字);
- 前端處理:
示例:
服務端返回 JSON:{ "id": 1234567890123456789 }
前端處理:
javascript
const numId = response.id;
const bigIntId = BigInt(response.id);
3. 框架 / 序列化工具的配置優(yōu)化
在前后端數(shù)據(jù)交互中(尤其是 JSON 序列化 / 反序列化),可通過工具配置自動處理大整數(shù):
例如,使用JSON.parse
時,通過reviver
函數(shù)將大整數(shù)轉換為BigInt
:
javascript
const data = JSON.parse(response, (key, value) => {
if (key === 'id' && typeof value === 'number' && value > 2**53 - 1) {
return BigInt(value);
}
return value;
});
部分框架(如 Vue、React)或 HTTP 客戶端(如 Axios)可配置攔截器,自動將大整數(shù)字段轉換為BigInt
或字符串。
四、注意事項
- 兼容性:
BigInt
在 IE 瀏覽器中不支持,但現(xiàn)代瀏覽器(Chrome、Firefox、Edge 等)均已支持; - 字符串傳遞的優(yōu)勢:若前端僅需展示或傳遞 ID(無需數(shù)值運算),字符串形式更簡單,避免
BigInt
的類型轉換成本; - 數(shù)據(jù)庫交互:若前端需將 ID 回傳到服務端或存儲到數(shù)據(jù)庫,保持字符串或
BigInt
類型即可(服務端可再轉換為 Int64 處理)。
總結
當服務端的 Int64 數(shù)值超過2^53 - 1
時,JavaScript 的number
類型無法精確表示,導致數(shù)值不匹配。解決核心是避開number
的精度限制,推薦通過 “字符串傳遞” 或 “前端BigInt
處理” 兩種方式,尤其在雪花算法 ID 等 64 位整數(shù)場景中必須使用。
?轉自https://juejin.cn/post/7524645466745815059
該文章在 2025/7/10 9:46:53 編輯過