在前端工作中,我们常常需要处理二进制数据,例如在 WebSocket 通讯协议中传输二进制数据等。而 Node.js 自带的 Buffer 对象可以很好地处理二进制数据。但是,在前端领域中,我们需要处理的二进制数据往往比较大,一次完整读取可能会占用过多内存或者导致 UI 卡顿等问题。buffer-queue 是一个基于 Node.js Buffer 对象的 npm 包,可以帮助我们高效地处理大量的二进制数据。
Buffer 和 buffer-queue 简介
Buffer
Buffer 是 Node.js 中提供的一个提供操作二进制数据的对象。可以理解为一个字节数组,用于存储二进制数据。Buffer 对象的内存是在堆外申请的,属于 Node.js 的 C++ 扩展,因此在使用 Buffer 时需要注意内存使用情况。
buffer-queue
buffer-queue 是一个使用方便且高效的处理大量二进制数据的 npm 包。它提供了一个 Buffer 队列,可以将一次完整数据拆分成多个小块放入队列,并提供一些方法可以让我们方便地从队列中读取和删除数据,同时也能维护内存使用的最佳状态。
安装 buffer-queue
安装 buffer-queue 模块可以使用 npm 命令:
npm install buffer-queue --save
使用 buffer-queue
buffer-queue 的 API 完全继承了 Node.js Buffer 对象,因此我们可以用与 Buffer 相同的方式来操作 queue。
创建 queue
使用 new bufferQueue() 函数可以创建一个空的 queue。
const bufferQueue = require('buffer-queue'); const queue = new bufferQueue();
向 queue 写入数据
我们可以使用 write() 函数将数据写入 queue 中:
const data = Buffer.from('hello world'); queue.write(data);
write() 函数接受一个参数 data,表示写入的数据,数据类型必须是 Buffer 或者是可转化为 Buffer 的类型。
除了 write() 函数之外,queue 还提供了一些与 Buffer 类似的写入方法:
- queue.writeUInt8(value[, offset])
- queue.writeUInt16BE(value[, offset])
- queue.writeUInt16LE(value[, offset])
- queue.writeUInt32BE(value[, offset])
- queue.writeUInt32LE(value[, offset])
- ...
以 writeUInt8() 为例,用法与 Buffer.writeUInt8() 完全一致:
queue.writeUInt8(10); // 向队列写入 1 个字节,在队尾追加
读取 queue 中的数据
使用 read() 函数可以读取 queue 中的数据:
const data = queue.read(len);
read() 函数接受一个参数 len,表示读取的数据长度。函数返回值为 Buffer 类型的数据。
如果 len 没有指定,则读取整个 queue 中的数据,即当前 queue 中所有的数据。
如果 queue 中没有数据可读,则 read() 返回 null。
常常需要在 read() 函数前先使用 length 属性确认 queue 中是否有数据可以读取:
if (queue.length > 0) { const data = queue.read(); // 进行数据处理 }
除了 read() 函数之外,queue 还提供了一些与 Buffer 类似的读取方法:
- queue.readUInt8([offset])
- queue.readUInt16BE([offset])
- queue.readUInt16LE([offset])
- queue.readUInt32BE([offset])
- queue.readUInt32LE([offset])
- ...
以 readUInt8() 为例,用法与 Buffer.readUInt8() 完全一致:
const value = queue.readUInt8(0); // 读取队列中第 1 个字节的值
删除 queue 中的数据
可以使用 consume() 函数删除 queue 中的数据:
queue.consume(len);
consume() 函数接受一个参数 len,表示要删除的字节数。如果 len 没有传入,则默认删除 queue 中所有数据。
常常需要在 consume() 前先使用 length 属性确认 queue 中是否有数据可删除:
if (queue.length > 0) { const len = 10; queue.consume(len); // 进行数据处理 }
将 queue 转化为 Buffer
使用 toBuffer() 函数可以将整个 queue 转化为一个 Buffer 对象:
const buf = queue.toBuffer();
其他方法
- queue.length:返回 queue 中数据的字节数
- queue.clear():清空 queue 中所有数据
- queue.destroy():销毁 queue,释放掉内存
使用示例
下面是一个使用 buffer-queue 的示例,我们可以读取一个远程二进制文件,并以 http response 的形式返回给浏览器:
-- -------------------- ---- ------- ----- ---- - ---------------- ----- ----------- - ------------------------ ----- ------- - ------------------- ----------------------- ---- -- - ----- ----- - --- -------------- ------------------------------------------ --------------- ---------- -- - ----- ------------- - -------------------------------------------- ---- ----------------------------- ---------------------------- ------------------------------- --------------- ------------------- ------- -- - ------------------- ------------------------ ---------------------------- --- ------------------ -- -- - ------------------------ ---------- --- -- ------------- ----------------
在这个示例中,使用 http 模块创建了一个 http 服务器,当有请求时,会向远程服务器请求一个 content-type 为 application/octet-stream 的文件。当 response 对象可读时,将数据写入 queue,同时从 queue 中读取并发送到浏览器。为了避免内存溢出,我们将大文件的数据拆分成小块,每个块读取一部分的数据,发送给浏览器之后再删除掉相应的数据。
指导意义
使用 buffer-queue 能够帮我们更加高效地处理大量的二进制数据,尤其是在网络通讯场景下,可以有效避免内存泄漏等问题。buffer-queue 的 API 与 Node.js Buffer 完全一致,用法非常容易上手。希望本篇文章能够帮到你更好地理解 buffer-queue,并能够应用到实际工作中。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/5f791fbe7116197505561b0f