问题:
在前后端分离的项目中,常常存在后端返回的数据长度过长,前端拿到数据时数据不准确,精度丢失。
JavaScript 能够准确表示的整数范围在-2^53到 2^53之间(不含两个端点),超过这个范围,无法精确表示这个值。
举个列子:
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({ storeAsString: true})
axiosInstance.defaults.transformResponse = [(data) => {
try {
return JSONbigString.parse(data)
} catch (error) {
return data
}
}]
// options.storeAsString, boolean值, 默认值:false
// 指定BigInts是否应该以字符串的形式存储在对象中,而不是默认的BigNumber。
// 请注意,这是一种危险的行为,因为它破坏了在不更改数据类型的情况下来回转换的默认功能(因为这将把所有bigint转换为be-and-stay字符串。