2月阅读周·深入浅出的Node.js | 文件与网络的二进制数据处理,从理解Buffer开始

举报
叶一一 发表于 2024/02/26 10:04:45 2024/02/26
【摘要】 背景去年下半年,我在微信书架里加入了许多技术书籍,各种类别的都有,断断续续的读了一部分。没有计划的阅读,收效甚微。新年伊始,我准备尝试一下其他方式,比如阅读周。每月抽出1~2个非连续周,完整阅读一本书籍。这个“玩法”虽然常见且板正,但是有效。已读完书籍:《架构简洁之道》。当前阅读周书籍:《深入浅出的Node.js》。理解BufferBuffer结构模块结构Buffer是一个典型的JavaSc...

背景

去年下半年,我在微信书架里加入了许多技术书籍,各种类别的都有,断断续续的读了一部分。

没有计划的阅读,收效甚微。

新年伊始,我准备尝试一下其他方式,比如阅读周。每月抽出1~2个非连续周,完整阅读一本书籍。

这个“玩法”虽然常见且板正,但是有效。

已读完书籍《架构简洁之道》。

当前阅读周书籍《深入浅出的Node.js》

理解Buffer

Buffer结构

模块结构

Buffer是一个典型的JavaScript与C++结合的模块,它将性能相关部分用C++实现,将非性能相关的部分用JavaScript实现。

6-1.png

Buffer对象

Buffer对象类似于数组,它的元素为16进制的两位数,即0到255的数值。

var str = "深入浅出node.js";
var buf = new Buffer(str, 'utf-8');
console.log(buf); // <Buffer e6 b7 b1 e5 85 a5 e6 b5 85 e5 87 ba 6e 6f 64 65 2e 6a 73>

Buffer内存分配

Buffer对象的内存分配不是在V8的堆内存中,而是在Node的C++层面实现内存的申请的。

为了高效地使用申请来的内存,Node采用了slab分配机制,slab是一种动态内存管理机制。

slab具有如下3种状态:

  • full:完全分配状态。
  • partial:部分分配状态。
  • empty:没有被分配状态。

Buffer的转换

Buffer对象可以与字符串之间相互转换。目前支持的字符串编码类型有:ASCII、UTF-8、UTF-16LE/UCS-2、Base64、Binary、Hex。

字符串转Buffer

字符串转Buffer对象主要是通过构造函数完成。

语法如下:

new Buffer(str, [encoding]);

通过构造函数转换的Buffer对象,存储的只能是一种编码类型。encoding参数不传递时,默认按UTF-8编码进行转码和存储。

const buf = new Buffer('node.js');
console.log(buf); // <Buffer 6e 6f 64 65 2e 6a 73>

Buffer转字符串

Buffer对象的toString()可以将Buffer对象转换为字符串。

语法如下:

buf.toString([encoding], [start], [end])

可以设置encoding(默认为UTF-8)、start、end这3个参数实现整体或局部的转换。

const str = buf.toString();
console.log(str); // node.js

Buffer不支持的编码类型

Node的Buffer对象支持的编码类型有限,只有少数的几种编码类型可以在字符串和Buffer之间转换。为此,Buffer提供了一个isEncoding()函数来判断编码是否支持转换。

语法如下:

Buffer.isEncoding(encoding)

我们来挑几个类型测试一下:

console.log(Buffer.isEncoding('utf8')) // true
console.log(Buffer.isEncoding('hex')) // true
console.log(Buffer.isEncoding('UTF-8')) // true
console.log(Buffer.isEncoding('Base64')) // true
console.log(Buffer.isEncoding('utf/8')) // false

Buffer的拼接

Buffer在使用场景中,通常是以一段一段的方式传输。想要进行拼接,可以用一个数组来存储接收到的所有Buffer片段并记录下所有片段的总长度,然后调用Buffer.concat()方法生成一个合并的Buffer对象。

Buffer.concat()方法封装了从小Buffer对象向大Buffer对象的复制过程。

const buf1 = Buffer.from('node');
const buf2 = Buffer.from('.');
const buf3 = Buffer.from('js');
const arr = [buf1, buf2, buf3];
const bufres = Buffer.concat(arr);
console.log(bufres.toString()); // node.js

Buffer与性能

在Web应用中,字符串转换到Buffer是时时刻刻发生的,提高字符串到Buffer的转换效率,可以很大程度地提高网络吞吐率。

在Node构建的Web应用中,可以选择将页面中的动态内容和静态内容分离,静态内容部分可以通过预先转换为Buffer的方式,可以有效地减少CPU的重复使用,节省服务器资源,使性能得到提升。

由于文件自身是二进制数据,所以在不需要改变内容的场景下,尽量只读取Buffer,然后直接传输,不做额外的转换,避免损耗。

总结

我们来总结一下本篇的主要内容:

  • Buffer是二进制数据,字符串与Buffer之间存在编码关系。
  • Buffer对象的真正的内存是在Node的C++层面提供的,JavaScript层面只是使用它。
  • 当进行小而频繁的Buffer操作时,采用slab的机制进行预先申请和事后分配,使得JavaScript到操作系统之间不必有过多的内存申请方面的系统调用。对于大块的Buffer而言,则直接使用C++层面提供的内存,而无需细腻的分配操作。
  • 通过预先转换静态内容为Buffer对象,可以有效地减少CPU的重复使用,节省服务器资源,提升性能。
  • 由于文件自身是二进制数据,所以在不需要改变内容的场景下,尽量只读取Buffer,然后直接传输,不做额外的转换,避免损耗。

作者介绍
非职业「传道授业解惑」的开发者叶一一。
《趣学前端》、《CSS畅想》等系列作者。华夏美食、国漫、古风重度爱好者,刑侦、无限流小说初级玩家。
如果看完文章有所收获,欢迎点赞👍 | 收藏️ | 留言📝

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。