json-bigint处理数值类型数据精度丢失

3,568 阅读2分钟

问题:

在前后端分离的项目中,常常存在后端返回的数据长度过长,前端拿到数据时数据不准确,精度丢失。

JavaScript 能够准确表示的整数范围在-2^53到 2^53之间(不含两个端点),超过这个范围,无法精确表示这个值。

image.png

举个列子:

Math.pow(2, 53// 9007199254740992`

9007199254740992 // 9007199254740992`

9007199254740993 // 9007199254740992`

 

Math.pow(2, 53) === Math.pow(2, 53) + 1 // true

上面代码中,超出 2 的 53 次方之后,一个数就不精确了。

ES6 引入了MAX_SAFE_INTEGER,表示 js 里最大的数值,比这更大的表示 Infinity,与之相对的是 Number.MIN_VALUE

前后端分离的项目中数据处理解决方案:

后端返回的数据一般都是 JSON 格式的字符串,'{ "id":900719925474099122}'。

axios库源码解析参考:segmentfault.com/a/119000001…

一般引入的axios库 为了方便我们使用数据,它会在内部使用 JSON.parse() 把后端返回的数据转为 JavaScript 对象。

可以看到,超出安全整数范围的 id 无法精确表示,这个问题并不是 axios 的错。

解决方案:

1、引入 json-bigint

// json-bigint 可以处理数据中超出 JavaScript 安全整数范围的问题

const jsonStr = '{ "id":900719925474099122}'

console.log(JSONBig.parse(jsonStr)) // 把 JSON 格式的字符串转为 JavaScript 对象

// 使用的时候需要把 BigNumber 类型的数据转为字符串来使用

  console.log(JSONBig.parse(jsonStr).id.toString()) //  900719925474099122

2、重写axios的transformResponse方法

import JSONBig from 'json-bigint'

const JSONbigString = JSONBig({ storeAsStringtrue})

axiosInstance.defaults.transformResponse = [(data) => {
    try {
        return  JSONbigString.parse(data)
    }   catch  (error) {
        return  data
    }
}]

// options.storeAsString, boolean值, 默认值:false

// 指定BigInts是否应该以字符串的形式存储在对象中,而不是默认的BigNumber。

// 请注意,这是一种危险的行为,因为它破坏了在不更改数据类型的情况下来回转换的默认功能(因为这将把所有bigint转换为be-and-stay字符串。