共计 2013 个字符,预计需要花费 6 分钟才能阅读完成。
什么是最大安全整数?
MAX_SAFE_INTEGER 是一个值为 9007199254740991 的常量。因为 Javascript 的数字存储使用了 IEEE 754 中规定的双精度浮点数数据类型,而这一数据类型能够安全存储 -(253 – 1) 到 253 – 1 之间的数值(包含边界值)。— MDN WEB DOCS
在项目会导致什么错误?
在代码中输出比 MAX_SAFE_INTEGER 大的 Number 值
console.log(9007199254740999) // 9007199254741000
console.log(9007199254740993) // 9007199254740992
在代码中比较超出安全存储的数值,可能会存在下列情况
9007199254740993 === 9007199254740992 // true
实际项目中碰到的问题
在进行 vue 项目开发的时候,通过 axios 进行前后端数据交互
后端在定义某些数据时将数据的 ID 设置为比 MAX_SAFE_INTEGER 大的 int 类型
而我取到后也没有注意到这一情况,在修改某一条数据时,是通过传回数据 ID 进行数据定位的。
然后问题就出现了。。。。
数据死活修改不了,后端返回无这条数据,调试了半天,
然后通过对比 preview 和 response 中的数据发现了两者数据不一致
如何解决?
第一个想法是在 axios 的拦截器中做处理, 将数字类型转换为字符串
9007199254740993 => '9007199254740993'
但经过尝试后发现 axios 拦截器中的数据本身就是错误了。
然后就用了原生的 fetch 做处理
export function getData(data) {const promise = new Promise(function (resolve, reject) {const headers = new Headers()
headers.append('Content-Type', 'application/json')
const config = {method: 'POST', headers, body: JSON.stringify(data) }
fetch('api/url', config).then(res => res.text()).then(text => {function numberToString (match) {return `:"${match.substring(1, match.length - 1)}",`
}
const responseJson = JSON.parse(text.replace(/:\d{15,100},/g, numberToString))
resolve(responseJson)
})
})
return promise
}
但问题是这个只解决了一个 api 的问题,然后每个都这样写,太烦了。
而且 fetch 并没有 axios 中的拦截器,不能统一处理异常
所有便想要自己封装一个 fetch 通过模仿 axios 那样设置拦截器之类的功能。。。。。。
然后就没有然后了,感觉封装一个目前需要的 fetch 会花个半天到一天的时间。
而且又快下班了,所以就去看 axios 文档了。
发现 axios 文档中已经有这样一个回调函数,能解决这个问题
// `transformResponse` allows changes to the response data to be made before
// it is passed to then/catch
transformResponse: [function (data) {
// Do whatever you want to transform the data
return data;
}],
这个不看文档的坏习惯,浪费了大半天时间
最后代码
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API, // api 的 base_url
timeout: 5*1000, // request timeout
transformResponse: [function (data) {function numberToString (match) {return `:"${match.substring(1, match.length - 1)}",`
}
if (isJSON(data)) {const responseJson = JSON.parse(data.replace(/:\d{15,100},/g, numberToString))
return responseJson
} else {return data}
}]
})
总结
第一,我这个数据是 json 类型的的所以在取到原始数据就是字符串,其实是对字符串进行处理
第二,最后的方案不是最优的,应为这个会处理每一条数据,不管那条数据中有没有超出范围的数字
第三,能想到的比较好的方案是和后端对接时问清楚那些是超出的,然后将这两种情况区分开来,再使用不同的 axios 封装