搜索
首页web前端js教程简单理解一下Node.js中的Buffer模块

简单理解一下Node.js中的Buffer模块

Nov 24, 2021 pm 07:20 PM
buffernode.js

本篇文章带大家了解一下Node.js中的Buffer,看看Buffer结构、Buffer内存分配、Buffer的拼接等,希望对大家有所帮助!

简单理解一下Node.js中的Buffer模块

理解Buffer

JavaScript对于字符串的操作十分友好

Buffer是一个像Array的对象,主要用于操作字节。

Buffer结构

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

1.png

Buffer所占用的内存不是通过V8分配,属于堆外内存。 由于V8垃圾回收性能影响,将常用的操作对象用更高效和专有的内存分配回收政策来管理是个不错的思路。

Buffer在Node进程启动时就已经价值,并且放在全局对象(global)上。所以使用buffer无需require引入

Buffer对象

Buffer对象的元素未16进制的两位数,即0-255的数值

let buf01 = Buffer.alloc(8);
console.log(buf01);  // <Buffer 00 00 00 00 00 00 00 00>

可以使用fill填充buf的值(默认为utf-8编码),如果填充的值超过buffer,将不会被写入。

如果buffer长度大于内容,则会反复填充

如果想要清空之前填充的内容,可以直接fill()

buf01.fill(&#39;12345678910&#39;)

console.log(buf01);   // <Buffer 31 32 33 34 35 36 37 38>
console.log(buf01.toString()); // 12345678

如果填入的内容是中文,在utf-8的影响下,中文字会占用3个元素,字母和半角标点符号占用1个元素。

let buf02 = Buffer.alloc(18, &#39;开始我们的新路程&#39;, &#39;utf-8&#39;);
console.log(buf02.toString());  // 开始我们的新

BufferArray类型影响很大,可以访问length属性得到长度,也可以通过下标访问元素,也可以通过indexOf查看元素位置。

console.log(buf02);  // <Buffer e5 bc 80 e5 a7 8b e6 88 91 e4 bb ac e7 9a 84 e6 96 b0>
console.log(buf02.length)  // 18字节
console.log(buf02[6])  // 230: e6 转换后就是 230
console.log(buf02.indexOf(&#39;我&#39;))  // 6:在第7个字节位置
console.log(buf02.slice(6, 9).toString())  // 我: 取得<Buffer e6 88 91>,转换后就是&#39;我&#39;

如果给字节赋值不是0255之间的整数,或者赋值时小数时,赋值小于0,将该值逐次加256.直到得到0255之间的整数。如果大于255,就逐次减去255。 如果是小数,舍去小数部分(不做四舍五入)

Buffer内存分配

Buffer对象的内存分配不是在V8的堆内存中,而是在Node的C++层面实现内存的申请。 因为处理大量的字节数据不能采用需要一点内存就向操作系统申请一点内存的方式。为此Node在内存上使用的是在C++层面申请内存,在JavaScript中分配内存的方式

Node采用了slab分配机制slab是以中动态内存管理机制,目前在一些*nix操作系统用中有广泛的应用,比如Linux

slab就是一块申请好的固定大小的内存区域,slab具有以下三种状态:

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

Node以8KB为界限来区分Buffer是大对象还是小对象

console.log(Buffer.poolSize);  // 8192

这个8KB的值就额是每个slab的大小值,在JavaScript层面,以它作为单位单元进行内存的分配

分配小buffer对象

如果指定Buffer大小小于8KB,Node会按照小对象方式进行分配

  1. 构造一个新的slab单元,目前slab处于empty空状态

2.png

  1. 构造小buffer对象1024KB,当前的slab会被占用1024KB,并且记录下是从这个slab的哪个位置开始使用的

3.png

  1. 这时再创建一个buffer对象,大小为3072KB。 构造过程会判断当前slab剩余空间是否足够,如果足够,使用剩余空间,并更新slab的分配状态。 3072KB空间被使用后,目前此slab剩余空间4096KB。

4.png

  1. 如果此时创建一个6144KB大小的buffer,当前slab空间不足,会构造新的slab(这会造成原slab剩余空间浪费)

5.png

比如下面的例子中:

Buffer.alloc(1)
Buffer.alloc(8192)

第一个slab中只会存在1字节的buffer对象,而后一个buffer对象会构建一个新的slab存放

由于一个slab可能分配给多个Buffer对象使用,只有这些小buffer对象在作用域释放并都可以回收时,slab的空间才会被回收。 尽管只创建1字节的buffer对象,但是如果不释放,实际是8KB的内存都没有释放

小结:

真正的内存是在Node的C++层面提供,JavaScript层面只是使用。当进行小而频繁的Buffer操作时,采用slab的机制进行预先申请和时候分配,使得JavaScript到操作系统之间不必有过多的内存申请方面的系统调用。 对于大块的buffer,直接使用C++层面提供的内存即可,无需细腻的分配操作。

Buffer的拼接

buffer在使用场景中,通常是以一段段的方式进行传输。

const fs = require(&#39;fs&#39;);

let rs = fs.createReadStream(&#39;./静夜思.txt&#39;, { flags:&#39;r&#39;});
let str = &#39;&#39;
rs.on(&#39;data&#39;, (chunk)=>{
    str += chunk;
})

rs.on(&#39;end&#39;, ()=>{
    console.log(str);
})

以上是读取流的范例,data时间中获取到的chunk对象就是buffer对象。

但是当输入流中有宽字节编码(一个字占多个字节)时,问题就会暴露。在str += chunk中隐藏了toString()操作。等价于str = str.toString() + chunk.toString()

下面将可读流的每次读取buffer长度限制为11.

fs.createReadStream(&#39;./静夜思.txt&#39;, { flags:&#39;r&#39;, highWaterMark: 11});

输出得到:

6.png

上面出现了乱码,上面限制了buffer长度为11,对于任意长度的buffer而言,宽字节字符串都有可能存在被截断的情况,只不过buffer越长出现概率越低。

encoding

但是如果设置了encodingutf-8,就不会出现此问题了。

fs.createReadStream(&#39;./静夜思.txt&#39;, { flags:&#39;r&#39;, highWaterMark: 11, encoding:&#39;utf-8&#39;});

7.png

原因: 虽然无论怎么设置编码,流的触发次数都是一样,但是在调用setEncoding时,可读流对象在内部设置了一个decoder对象。每次data事件都会通过decoder对象进行buffer到字符串的解码,然后传递给调用者。

string_decoder 模块提供了用于将 Buffer 对象解码为字符串(以保留编码的多字节 UTF-8 和 UTF-16 字符的方式)的 API

const { StringDecoder } = require(&#39;string_decoder&#39;);
let s1 = Buffer.from([0xe7, 0xaa, 0x97, 0xe5, 0x89, 0x8d, 0xe6, 0x98, 0x8e, 0xe6, 0x9c])
let s2 = Buffer.from([0x88, 0xe5, 0x85, 0x89, 0xef, 0xbc, 0x8c, 0x0d, 0x0a, 0xe7, 0x96])
console.log(s1.toString());
console.log(s2.toString());
console.log(&#39;------------------&#39;);

const decoder = new StringDecoder(&#39;utf8&#39;);
console.log(decoder.write(s1));
console.log(decoder.write(s2));

8.png

StringDecoder在得到编码之后,知道了宽字节字符串在utf-8编码下是以3个字节的方式存储的,所以第一次decoder.write只会输出前9个字节转码的字符,后两个字节会被保留在StringDecoder内部。

Buffer与性能

buffer在文件I/O和网络I/O中运用广泛,尤其在网络传输中,性能举足轻重。在应用中,通常会操作字符串,但是一旦在网络中传输,都需要转换成buffer,以进行二进制数据传输。 在web应用中,字符串转换到buffer是时时刻刻发生的,提高字符串到buffer的转换效率,可以很大程度地提高网络吞吐率。

如果通过纯字符串的方式向客户端发送,性能会比发送buffer对象更差,因为buffer对象无须在每次响应时进行转换。通过预先转换静态内容为buffer对象,可以有效地减少CPU重复使用,节省服务器资源。

可以选择将页面中动态和静态内容分离,静态内容部分预先转换为buffer的方式,使得性能得到提升。

在文件的读取时,highWaterMark设置对性能影响至关重要。在理想状态下,每次读取的长度就是用户指定的highWaterMark

highWaterMark大小对性能有两个影响的点:

  • 对buffer内存的分配和使用有一定影响
  • 设置过小,可能导致系统调用次数过多

更多node相关知识,请访问:nodejs 教程!!

以上是简单理解一下Node.js中的Buffer模块的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文转载于:掘金社区。如有侵权,请联系admin@php.cn删除
JavaScript的角色:使网络交互和动态JavaScript的角色:使网络交互和动态Apr 24, 2025 am 12:12 AM

JavaScript是现代网站的核心,因为它增强了网页的交互性和动态性。1)它允许在不刷新页面的情况下改变内容,2)通过DOMAPI操作网页,3)支持复杂的交互效果如动画和拖放,4)优化性能和最佳实践提高用户体验。

C和JavaScript:连接解释C和JavaScript:连接解释Apr 23, 2025 am 12:07 AM

C 和JavaScript通过WebAssembly实现互操作性。1)C 代码编译成WebAssembly模块,引入到JavaScript环境中,增强计算能力。2)在游戏开发中,C 处理物理引擎和图形渲染,JavaScript负责游戏逻辑和用户界面。

从网站到应用程序:JavaScript的不同应用从网站到应用程序:JavaScript的不同应用Apr 22, 2025 am 12:02 AM

JavaScript在网站、移动应用、桌面应用和服务器端编程中均有广泛应用。1)在网站开发中,JavaScript与HTML、CSS一起操作DOM,实现动态效果,并支持如jQuery、React等框架。2)通过ReactNative和Ionic,JavaScript用于开发跨平台移动应用。3)Electron框架使JavaScript能构建桌面应用。4)Node.js让JavaScript在服务器端运行,支持高并发请求。

Python vs. JavaScript:比较用例和应用程序Python vs. JavaScript:比较用例和应用程序Apr 21, 2025 am 12:01 AM

Python更适合数据科学和自动化,JavaScript更适合前端和全栈开发。1.Python在数据科学和机器学习中表现出色,使用NumPy、Pandas等库进行数据处理和建模。2.Python在自动化和脚本编写方面简洁高效。3.JavaScript在前端开发中不可或缺,用于构建动态网页和单页面应用。4.JavaScript通过Node.js在后端开发中发挥作用,支持全栈开发。

C/C在JavaScript口译员和编译器中的作用C/C在JavaScript口译员和编译器中的作用Apr 20, 2025 am 12:01 AM

C和C 在JavaScript引擎中扮演了至关重要的角色,主要用于实现解释器和JIT编译器。 1)C 用于解析JavaScript源码并生成抽象语法树。 2)C 负责生成和执行字节码。 3)C 实现JIT编译器,在运行时优化和编译热点代码,显着提高JavaScript的执行效率。

JavaScript在行动中:现实世界中的示例和项目JavaScript在行动中:现实世界中的示例和项目Apr 19, 2025 am 12:13 AM

JavaScript在现实世界中的应用包括前端和后端开发。1)通过构建TODO列表应用展示前端应用,涉及DOM操作和事件处理。2)通过Node.js和Express构建RESTfulAPI展示后端应用。

JavaScript和Web:核心功能和用例JavaScript和Web:核心功能和用例Apr 18, 2025 am 12:19 AM

JavaScript在Web开发中的主要用途包括客户端交互、表单验证和异步通信。1)通过DOM操作实现动态内容更新和用户交互;2)在用户提交数据前进行客户端验证,提高用户体验;3)通过AJAX技术实现与服务器的无刷新通信。

了解JavaScript引擎:实施详细信息了解JavaScript引擎:实施详细信息Apr 17, 2025 am 12:05 AM

理解JavaScript引擎内部工作原理对开发者重要,因为它能帮助编写更高效的代码并理解性能瓶颈和优化策略。1)引擎的工作流程包括解析、编译和执行三个阶段;2)执行过程中,引擎会进行动态优化,如内联缓存和隐藏类;3)最佳实践包括避免全局变量、优化循环、使用const和let,以及避免过度使用闭包。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

将Eclipse与SAP NetWeaver应用服务器集成。

mPDF

mPDF

mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中

Atom编辑器mac版下载

Atom编辑器mac版下载

最流行的的开源编辑器

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境