关闭

Js如何向 ArrayBuffer 写入Uint64数据?

时间: 2019-08-03阅读: 1627标签: 数据

js 的 Uint53

js 的 Number 精度只有 「-2^52 ~ 2^52 - 1」,可以通过 Number.MAX_SAFE_INTEGER 查看 JS 的安全运算范围。

由于这个原因,在一些需要更精确运算的应用场景中,JS Number 精度就不够了,例如需要把 64 位数字写入到 buffer 数组中。

那怎么解决 JS 的精度问题?


使用 BigInt

在最新的 stage3 中,引入了 BigInt API,用于解决超出 JS Number 运算范围的精度问题。

打开浏览器的控制台输入
BigInt(0)
// 输出 0n

在数字后面加 n 就是 BigInt 类型。

有 BigInt API 可以轻松向 buffer 写入 64 位的数据

const buffer = new ArrayBuffer(8);
const view = new DataView(buffer);

const offset = 0;
const littleEndian = true;

view.setBigUint64(offset, BigInt('123456789012412421521'), littleEndian);

console.log(view) // 刚好用 64 字节写满 8 位的 buffer

但是事情并没有那么一帆风顺,目前只有 Chrome 和 Firefox 等主流浏览器实现了,Safari 系列的 JavaScriptCore 引擎并不支持,需要用另外的方法兼容。

如何兼容不支持 BigInt 的 js 引擎?


使用 Chrome 团队出品的 JSBI

JSBI GitHub

可以兼容大数据运算的需求

import JSBI from 'jsbi'

// 官方例子,用 JS 最大长度 + 2
const max = JSBI.BigInt(Number.MAX_SAFE_INTEGER);
console.log(String(max));
// → '9007199254740991'
const other = JSBI.BigInt('2');
const result = JSBI.add(max, other);
console.log(String(result));

恨简单的使用方式,完美兼容。

但是这又如何在 buffer 中读写 64 位数据?


操作 buffer 中 64 位数据的方案

写一个 polyfill,在项目中引入,以下例子为 TS

import JSBI from 'jsbi';

declare global {
  interface DataView {
    setUint64: Function;
    getUint64: Function;
  }
}

DataView.prototype.setUint64 = function setUint64(
  byteOffset: number, value, littleEndian: boolean
) {
  if (typeof value === 'bigint' && typeof this.setBigUint64 !== 'undefined') {
    // the original native implementation for bigint
    this.setBigUint64(byteOffset, value, littleEndian);
  } else if (value.constructor === JSBI && typeof value.sign === 'bigint' && typeof this.setBigUint64 !== 'undefined') {
    // JSBI wrapping a native bigint
    this.setBigUint64(byteOffset, value.sign, littleEndian);
  } else if (value.constructor === JSBI) {
    // JSBI polyfill implementation
    const lowWord = value[0];
    let highWord = 0;
    if (value.length >= 2) {
      highWord = value[1];
    }
    this.setUint32(byteOffset + (littleEndian ? 0 : 4), lowWord, littleEndian);
    this.setUint32(byteOffset + (littleEndian ? 4 : 0), highWord, littleEndian);
  } else {
    throw TypeError('Value needs to be BigInt ot JSBI');
  }
};
DataView.prototype.getUint64 = function getUint64(byteOffset, littleEndian) {
  if (typeof this.getBigUint64 !== 'undefined') {
    return this.getBigUint64(byteOffset, littleEndian);
  }
  let lowWord = 0;
  let highWord = 0;
  lowWord = this.getUint32(byteOffset + (littleEndian ? 0 : 4), littleEndian);
  highWord = this.getUint32(byteOffset + (littleEndian ? 4 : 0), littleEndian);
  const result = new JSBI(2, false);
  result.__setDigit(0, lowWord);
  result.__setDigit(1, highWord);
  return result;
};

使用方式与 BigInt 类似

import JSBI from 'jsbi';

const buffer = new ArrayBuffer(8);
const view = new DataView(buffer);

const offset = 0;
const littleEndian = true;

// 使用 polyfill 的 api
view.setUint64(offset, JSBI.BigInt('123456789012412421521'), littleEndian);

console.log(view) // 得出的结果应该与原生方法保持一致的。


参考

可以参考 little-chat IM 客户端的实现

来自:https://segmentfault.com/a/1190000019962727


站长推荐

1.云服务推荐: 国内主流云服务商,各类云产品的最新活动,优惠券领取。地址:阿里云腾讯云华为云

2.广告联盟: 整理了目前主流的广告联盟平台,如果你有流量,可以作为参考选择适合你的平台点击进入

链接: http://www.fly63.com/article/detial/4471

关闭

前端数据模型Model;适用于多人团队协作的开发模式

本文讲述的数据模型并不是一个库,也不是需要npm的包,仅仅只是一种在多人团队协作开发的时候拟定的规则,也不用担心后台数据的字段或结构发生变动,真正实现前后台并行开发的愉快模式。

js进制数之间以及和字符之间的转换

js要处理十六进制,十进制,字符之间的转换,发现有很多差不多且书写不正确的方法.一个一个实践才真正清楚如何转换,现在来记录一下它们之间转换的方法。

Mock.js使用

Mock.js 是一款前端开发中拦截Ajax请求再生成随机数据响应的工具.可以用来模拟服务器响应. 优点是非常简单方便, 无侵入性, 基本覆盖常用的接口数据类型.大概记录下使用过程, 详细使用可以参见Mock文档 Mock Wiki

Js中实现XML和String相互转化

XML是标准通用标记语言 (SGML) 的子集,非常适合 Web 传输。XML 提供统一的方法来描述和交换独立于应用程序或供应商的结构化数据。 这篇文章主要介绍Js中实现XML和String相互转化

js判断数字是奇数还是偶数的2种方法实现

奇数和偶数的判断是数学运算中经常碰到的问题,这篇文章主要讲解通过JavaScript来实现奇偶数的判断。2种判断方法:求余% 、&1

17 款可视化工具,让你的数据更美观

想让数据变得更好看?不必成为经验丰富的数据科学家,也不必成为平面设计师。有一些能让数据从简单的表格变成多种多样的图形,地图甚至词“云”。并不是所有的工具都适合你,但这些工具确实很有用

Vue 数据更新了但页面没有更新的 7 种情况汇总及延伸总结

Vue 无法检测实例被创建时不存在于 data 中的 property原因:由于 Vue 会在初始化实例时对 property 执行 getter/setter 转化,所以 property 必须在 data 对象上存在才能让 Vue 将它转换为响应式的。

React中获取数据的3种方法:哪种最好?

在执行 I/O 操作(例如数据提取)时,要先发送网络请求,然后等待响应,接着将响应数据保存到组件的状态,最后进行渲染。在 React 中生命周期方法、Hooks和 Suspense是获取数据的方法。

Nginx返回大长度的JSON数据被截断

1 添加Nginx参数,增加缓存字符串大小;2 遇到权限问题,原因是大文件会先缓存到/proxy-temp文件夹下面,然后再返回;修改文件夹的权限为Nginx用户

哪种方式更适合在React中获取数据?

当执行像数据获取这样的I/O操作时,你必须发起获取请求,等待响应,将响应数据保存到组件的状态中,最后渲染。异步的数据获取会要求额外的工作来适应React的声明性,React也在逐步改进去最小化这种额外的工作

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!