Buffer 是一个典型的 JavaScript 与 C++结合的模块,其性能相关部分用 C++实现,非性能相关的用 js 实现。
Buffer 所占用的内存不是通过 V8 分配的,属于 V8 堆外内存。真正的内存是在 C++层面提供的,JavaScript 层面只是使用它:
- 小而频繁的 Buffer 操作,采用 slab 的机制(内存由 C++先申请、js 后分配,避免过多内存申请方面的系统调用)
- 大块的 Buffer 操作,直接使用 C++层面提供的内存,而无需细腻的分配操作
常用函数
new Buffer()已被弃用
-
Buffer.from
字符串转 Buffer -
buf.toString([encoding, start, end])
Buffer 转字符串 -
Buffer.isEncoding('GBK') === false
支持的编码类型有限 -
Buffer.alloc(size, [fill = 0, encoding = 'utf8'])
创建指定大小 Buffer- 给元素的赋值(合法值为 0 到 255 之间的整数):
- < 0,逐次+256 直至正常
-
255,逐次-256
- 小数,舍弃小数部分
- 给元素的赋值(合法值为 0 到 255 之间的整数):
-
buf.write(string,[offset = 0, length = string.length, encoding = 'utf8'])
向 Buffer 中写入数据:根据 encoding 将 string 写入 buf 的 offset 处 -
Buffer.concat(bufArray, allBufSize)
拼接 Buffer
拼接 Buffer
当两个 Buffer 相加时实际上buf1 + buf2 === buf1.toString() + buf2.toString()
。所以在操作流时的 data、end 事件回调,要小心操作数据,以免出现半个字符的情况导致乱码
给流指定编码可以修正此问题stream.setEncoding("utf8")
,但此方法仅支持 UTF-8、Base64 和 UCS-2/UTF-16LE 这 3 种编码。
Buffer.concat
方法需要把所有 buffer 先存放在一个临时变量,待拼接后再处理(V8 堆外内存,不够用的话就是另一个问题了)。
处理更多编码类型
iconv-lite 采用纯 JavaScript 实现,iconv 则通过 C++调用 libiconv 库完成。在性能方面,由于转码都是耗用 CPU,在 V8 的高性能下,少了 C++到 JavaScript 的层次转换,纯 JavaScript 的性能比 C++实现得更好。
iconv-lite 无法转换的内容如果是多字节,会输出 �;如果是单字节,则输出?
iconv 则有三级降级策略,可能设置为尝试翻译、忽略
var iconv = new Iconv("UTF-8", "ASCII//TRANSLIT//IGNORE");
iconv.convert("ça va が"); // "ca va "
性能
网络传输字符串时,会先将字符串转换为 Buffer 后再传输,所以静态内容预先转换为 Buffer 对象,可以减少 CPU 的重复使用,节省服务器资源。
文件操作时,highWaterMark 太大会浪费内存,过小可能导致系统调用次数过多。highWaterMark 越大读取速度越快。
网友评论