Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

备稿计划: 解决 BigInt JSON 化问题 #120

Open
iugo opened this issue Jul 22, 2022 · 0 comments
Open

备稿计划: 解决 BigInt JSON 化问题 #120

iugo opened this issue Jul 22, 2022 · 0 comments

Comments

@iugo
Copy link
Member

iugo commented Jul 22, 2022

当前, JS 的 JSON 方法均不支持 bigint.

json-parse-with-source 提案解决 BigInt JSON 化问题

如果想要保持向前兼容, 直接让 JS JSON 支持 bigint 是不行的.

不过, 有一些可插拔的办法, 比如最近刚进入 stage 3 的 https://github.com/tc39/proposal-json-parse-with-source 提案.

该提案的目的之一就是为了解决 bigint 不兼容问题, 官方例子如下:

const tooBigForNumber = BigInt(Number.MAX_SAFE_INTEGER) + 2n;
const intToBigInt = (key, val, {source}) => typeof val === "number" && val % 1 === 0 ? BigInt(source) : val;
const roundTripped = JSON.parse(String(tooBigForNumber), intToBigInt);
tooBigForNumber === roundTripped;
// → true

const bigIntToRawJSON = (key, val) => typeof val === "bigint" ? JSON.rawJSON(val) : val;
const embedded = JSON.stringify({ tooBigForNumber }, bigIntToRawJSON);
embedded === '{"tooBigForNumber":9007199254740993}';
// → true

看上去很好, 不过与我们之前的做法略有不兼容的是, 针对 bigint, 我们使用 string, 比如 1n 会被转为 "1".

不过我们之前还存在的问题是小于 MAX_SAFE_INTEGER 的 bigint, 到底是否需要保留?

我之前的做法是保留. 前后端通过中间层转换. 不过这样需要对类型非常明确, 每次做针对性的转换.

之前考虑过是否要写通用函数, 其实类似 JSON 方法第二个参数. 但是考虑到 "不知道哪些字符串该被转为 bigint", 所以放弃了通用做法, 而是使用中间层做有针对性的显性转换. 做针对性转换的一个好处就是可以区分 1n, 1, "1". 通用转换要不就是无法区分 1n"1", 要不就是无法区分
1n1.

如果既要通用, 又要支持区分, 就会像 DynamoDB 一样搞成 {type: "bigint", value: "1"}, {type: "int", value: "1"} 这样.

为什么需要将 BigInt JSON 化

我们现在会频繁遇到这个问题主要是因为 UNIX 时间戳, 在数据库中需要是 bigint (因为考虑到不远的 2038 年就会溢出 int), 但 JS 中的 MAX_SAFE_INTEGER 实际会较大, 有时我们会选择 number 来存放 UNIX 时间戳.

  • int4 最大 2147483647 Math.pow(Math.pow(2, 8), 4) 分两半, 正数占一半
  • Number.MAX_SAFE_INTEGER 9007199254740991 Math.pow(2, 53)

感觉 int4 就很讲理, 但 JS, 这 53, 就感觉不是那么讲理了.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant