JS 大数溢出问题

查看 232|回复 16
作者:justdoit123   
后端的大数到 JS 端 JSON.parse 之后,经常大数溢出。
这个问题之前一直是在后端看到一处,就 stringify 一处。现在实在是觉得烦了,想请教下各位有什么更好的做法?
查了些资料,这个溢出是在 JS 进程里 JSON.parse 的时候发生的,跟 JS 自身有关系,跟 JSON 没有关系。想着,在 JSON.parse 的时候,换成 BigInt 的 JSON.parse 。但是这其中也有两种策略:
1. 只要是整数,全部转成 BigInt ,不管实际会不会溢出。这样的好处是统一,坏处怕会有什么性能问题
2. 只有当一个整数会溢出的时候,才会转成 BigInt 。但是这样用的时候还需要做下判断,比较麻烦。
暂时想在内部后台系统里尝试下,浏览器兼容不成问题。有没有别的高招?
PS. 这个真是 JS 的天坑。

rse, 溢出, bigint, 大数

realJamespond   
让后端返回字符串再处理?
neotheone2333   
返字符串,内部再转 Bignumber.js 处理
justdoit123
OP
  
@realJamespond 就是不想再在后端转字符串了呀!
除非从 DB Access 层就把所有 bigint 都转成 string ,顺便好奇问下大家也是这么做的吗?像 timestamp 这种,在 db 里用 bigint 存储,但是使用的时候是实实在在要当数字使用的,如果转成 string 用的时候还要转回去。
debuggerx   
这个很多语言都有类似的问题,最简单的还是让后端把可能溢出的字段用字符串类型传过来,前端自己转
zjsxwc   
如下,JSON 里整数是 64 位的,但到了 js v8 里却不支持 64 位整数,目前主流 cpu 都是 64 位,64 位整数最大值是~(1<<63) = (1<<63) -1 = 9223372036854775807:
获得 json 格式的字符串
```
$ php -r "var_dump(json_encode(9223372036854775807));"
string(19) "9223372036854775807"
$ php -r "var_dump(json_encode(9223372036854775808));"
string(21) "9.223372036854776e+18"
```
js 解析就丢失精度了,9223372036854775807 变成了 9223372036854776000 ,最后几位全变 0 了:
```
JSON.parse("9223372036854775807")
9223372036854776000
```
cmdOptionKana   
唉,基础知识不能叫做“天坑”吧,浮点数处理本来就有很多注意事项,编程语言是设计给“专家”使用的,本来就不是面向 end user 的。
如果不是金融相关的,多数情况下都可以降低精度,如果确实需要很高精度,那也只好麻烦一点处理了。
icoomn   
之前也遇到这个问题,SQL 语句 select count() 查出来的数据默认就是 bigint 类型, 我是在后端直接做类型转换,将 bigint 转为 int 然后再返给前端的。
前端解决的话可以看下这个 JS 库:json-bigint
ZAnko   
我们也是后端处理成字符串返回的,如果一定要前端处理,可以试试利用第三方库在相应拦截中统一处理掉。
iOCZ   
一些第三方库(如 json-bigint )之所以能正确的处理大数 parse ,且不造成精度丢失,其实现原理也是类似。在拿到接口的 JSON 数据时,并不直接 JSON.parse ,而是先将整块数据当作 text 字符串,将其中的大数以 string 类型进行存储和标记,再使用定制化的 JSON.parse 。
自己处理的话,不外乎类似如此,可以单独抽取一个方法包裹 JSON.parse:
```javascript
var text = '{ "name":"Bill Gates", "birth":"1955-10-28", "city":"Seattle"}';
var obj = JSON.parse(text, function (key, value) {
if (key == "birth") {
return new Date(value);
} else {
return value;
}});
```
您需要登录后才可以回帖 登录 | 立即注册

返回顶部