JS踩坑實戰(zhàn)之19位數(shù)Number型精度丟失問題詳析
前言
這篇文章主要介紹了JS大坑之19位數(shù)的Number型精度丟失問題,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,有興趣的朋友們可以一起來學(xué)習(xí)探討。
最近在實現(xiàn)一個需求的時候,需要接入第三方的接口,先調(diào)用A接口,A接口返回的數(shù)據(jù)里,有一個taskId,然后再使用這個taskId請求B接口,獲取最終需要的數(shù)據(jù)。
后端使用的是node,因此最開始使用的是request-promise這個包請求第三方接口,然而在獲取A接口返回的taskId之后,調(diào)用B接口之后,B接口的響應(yīng)居然是系統(tǒng)錯誤!簡易代碼如下:
const rp = require('request-promise')
const { taskId } = await rp('https://xxx.com/A')
const options = {
method: 'POST',
uri: 'https://xxx.com/B',
body: {
taskId
},
json: true
}
const result = await rp(options)
// {
// "errorcode": "40001",
// "message": "系統(tǒng)錯誤",
// "status": "failed"
// }接著我使用postman請求A接口,獲取新的taskId,再用新的taskId請求B接口,結(jié)果卻是正常的!
我在反復(fù)檢查代碼,確認(rèn)請求的參數(shù)都是正常的格式之后,一時陷入了無盡的沉思之中……
發(fā)現(xiàn)
在做了幾次嘗試之后,我發(fā)現(xiàn)使用node請求得到的taskId最后兩位數(shù)都是0,即1152921504735848700,而使用postman獲取的taskId,則是比較正常的是1152921504735848759,接著我在node控制臺做如下操作:

就是這么一瞬間,頓悟了。A接口里的taskId是個19位數(shù)字,而request-promise在將數(shù)據(jù)解析成json時,導(dǎo)致這個19位的數(shù)字丟失了精度,查了下資料,發(fā)現(xiàn)js的number類型有個最大安全值,即2的53次方(9007199254740992),超過這個值就會出現(xiàn)精度丟失的問題。
獲取正確的響應(yīng)數(shù)據(jù)
由于在一開始使用request-promise包,因此獲取的taskId是丟失了精度了,因此改用了node原生的http模塊發(fā)送請求。
const req = https.request('https://xxx.com/A', (res) => {
res.on('data', (chunk) => {
// 由于這里獲取到的響應(yīng)數(shù)據(jù)是JSON字符串,因此19位的數(shù)字只是字符串的一部分,這時獲取到的taskId就是正確的數(shù)字
console.log(`BODY: ${chunk}`);
});
res.on('end', () => {
console.log('No more data in response.');
})
})雖然獲取到了正常的響應(yīng)數(shù)據(jù),但是這是個JSON字符串,接下來還要把這個字符串解析成JSON,但是用JSON.parse(),又會引起精度丟失的問題,這可真尷尬 ……
如果這個接口是已方可控的,那么就可以把這個19位數(shù)的number轉(zhuǎn)成字符串,這樣在解析的時候就不會出錯了,但是由于是第三方接口,因此沒法改變。那么最快的解決方案,就是換種編程語言請求啊。
最后的解決
好吧,最后還是用了node,不過我用了比較硬核的方案實現(xiàn),先在獲取的JSON字符串中,找到這個19位的數(shù)字,然后為它加上引號,這樣再用JSON.parse()解析的時候,就能保持正常的數(shù)值,這樣接下的流程就自然通了,代碼如下:
let result = '{"taskId":1152921504735848759,"status":"CREATED","progress":0.0,"success":true}'
// JSON.parse(result) 不為19位數(shù)補(bǔ)上雙引號,直接parse時,精度丟失,結(jié)果如下:
// {
// taskId: 1152921504735848700,
// status: 'CREATED',
// progress: 0,
// success: true
// }
const taskId = result.match(/[0-9]{19}/)[0] // 正則獲取19位數(shù)字的值
result = result.replace(taskId,`"${taskId}"`) // 補(bǔ)上雙引號
const data = JSON.parse(result)
// {
// taskId: '1152921504735848759', // 解析出來之后是字符串,因此沒有丟失精度
// status: 'CREATED',
// progress: 0,
// success: true
// }總結(jié)
到此這篇關(guān)于JS踩坑實戰(zhàn)之19位數(shù)Number型精度丟失問題的文章就介紹到這了,更多相關(guān)JS Number型精度丟失問題內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
微信小程序tabBar模板用法實例分析【附demo源碼下載】
這篇文章主要介紹了微信小程序tabBar模板用法,結(jié)合具體實例形式分析了tabBar模板的定義、配置、引用等相關(guān)操作技巧,需要的朋友可以參考下2017-11-11
Bootstrap table 服務(wù)器端分頁功能實現(xiàn)方法示例
這篇文章主要介紹了Bootstrap table 服務(wù)器端分頁功能實現(xiàn)方法,結(jié)合實例形式詳細(xì)分析了Bootstrap table 服務(wù)器端后臺交互與分頁功能相關(guān)操作技巧,需要的朋友可以參考下2020-06-06
JS實現(xiàn)商城秒殺倒計時功能(動態(tài)設(shè)置秒殺時間)
這篇文章主要介紹了JS實現(xiàn)商城秒殺倒計時功能(動態(tài)設(shè)置秒殺時間),本文通過實例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2019-12-12
JavaScript無提示關(guān)閉窗口(兼容IE/Firefox/Chrome)
JavaScript無提示關(guān)閉當(dāng)前頁面窗口,兼容IE/Firefox/Chrome (Close the current page window without confirm by JavaScript, support all browsers)2008-11-11

