您已经成为Node开发人员多年了,但是从未遇到过Node Buffers吗?也许您遇到过几次该术语,但是总是回避学习什么是缓冲区?您可能实际上从未真正需要使用缓冲区。Node.js并不是迫使程序员直接处理程序如何管理内存的语言。但是,如果您致力于成为一名专业的Node开发人员,那么您就必须努力解决诸如缓冲区之类的概念,以了解Node的工作原理。
乍一看,您会觉得节点缓冲区是一个很难理解的话题。但实际上并非如此。当您查看的所有在线教程都从创建节点缓冲区并对其进行操作而没有首先说明实际缓冲区是什么时,问题就开始了。为了避免在这里犯同样的错误,我必须先解释什么是缓冲区。但是在了解什么是缓冲区之前,我们必须解决尝试理解缓冲区时出现的其他一些概念。
为了正确理解缓冲区,我们应该了解二进制数据,字符编码和流。如果您还没有看到这些东西对缓冲区有何影响,请不用担心,它们全部在一起,最后解释缓冲区是什么。
1. 什么是二进制数据?
如果您已经知道什么是二进制数据,则可以直接跳到下一个主题。其他人应该坚持看看什么是二进制数据。
二进制数字系统是另一个数字系统,例如我们使用的十进制数字系统。与十进制数制不同,十进制数制使用0-9的数字表示数字,而二进制数制仅使用数字0和1表示数字。这是二进制数的一些示例。
0, 1, 10, 101, 1011011, 1000101
二进制数中的每个数字在计算机科学中均被视为一个位。8位的组合称为Byte。但是计算机科学与二进制数有什么关系?计算机使用二进制数字来存储和表示数据。因此,存储在计算机中的每种数据最终都将存储为一组二进制数。我们称这些数据为二进制数据。
为了将每种类型的数据存储为二进制数据,计算机应该知道如何将它们转换为二进制数据。计算机具有实现此目的的不同机制。让我们看看它们是什么。
计算机如何将数字转换为二进制数据?
将数字转换为二进制数据只是数学上的事情。您可以参考二进制数字运算和数字系统转换所涉及的数学知识,以了解更多信息。但是,使用此数学运算,十进制数字9可以二进制表示为101,其他整数也可以表示为101。计算机具备自行进行此转换的能力。
计算机如何将字符转换为二进制数据?
对这个问题的简单解释是“每个字符都有一个与之关联的唯一二进制数”。此唯一数字称为字符的代码点或字符代码。您可以使用charCodeAtJavascript中的函数查找每个字符的字符代码。
'a'.charCodeAt() //outputs 97
'A'.charCodeAt() //outputs 65
有两个主要标准用于为每个字符分配字符代码:ASCII和Unicode。无论使用哪种编程语言,赋予字符的字符代码都相同。ASCII最多使用7位来表示字符,而Unicode最多使用16位。这种差异为Unicode提供了比ASCII更大的范围,以表示更多的字符,并使Unicode成为两者中最受欢迎的标准。
计算机将字符转换为二进制数据所需要做的唯一工作就是查找每个字符的字符点吗?答案是:否。还有一个将字符转换为二进制数据的步骤。那就是字符编码。
2. 什么是字符编码?
我之前提到过ASCII最多可以使用7位,而Unicode最多可以使用16位来表示字符。但是计算机不必总是使用Unicode的所有16位来表示字符。例如,字符“ A”可以使用最少7位来表示。如果计算机通过用前导0填充二进制数来使用16位来存储“ A”,则将浪费系统资源。
这就是字符编码的介入之处。字符编码标准决定了计算机用来表示字符的位数。UTF-8,UTF-16和UTF-32是字符编码标准的一些示例。
UTF-8使用8位(字节)的块表示字符。它可以使用1-4个字节对所有Unicode字符进行编码。现在,如果计算机使用UTF-8标准对“ A”进行编码,则存储的二进制值为01000001,前导0。
这样就完成了将字符转换为二进制数据的过程。将字符串转换为二进制数据无非就是将每个字符转换为二进制数据。计算机使用更多的标准和方法将图像,音频和视频数据转换为二进制数据。
现在出现了Streams的概念。让我们看看它们是什么。
3. 什么是流?
流是从一处移到另一处的数据集合。在我们的例子中,我们谈论的是二进制数据流,它们是从一个地方移动到另一个地方的二进制数据的集合。
流包含大量数据。但是计算机不必等待流中的所有数据都可以开始处理。当将流发送到某个目的地时,由于其大小太大,因此不会立即发送流中的数据。而是将流分为较小的数据块。目标收集接收的块,并在有足够的块可用时开始处理它们。
接收流的目标旨在以某种方式处理数据-读取,操作或写入数据。但是目的地处的数据处理器的容量限制了它一次可以处理的最大和最小数据量。那么,当目标接收到不符合此限制的数据块时会发生什么呢?目的地无法丢弃它们。然而,目的地可以使用一种机制来存储接收到的块,直到它们被处理器接受为止。这是缓冲区介入的地方。但是,首先,我们应该知道缓冲区到底是什么,以了解它们如何帮助存储数据块。
4. 什么是缓冲区,它们做什么?
缓冲区是计算机内存(通常是RAM)中较小的存储空间。在目标处理器准备好接受来自流的接收数据块之前,缓冲区充当它们的等待区域。
如果目标从流中接收数据的速度快于其处理数据的速度,则这些多余的数据将在缓冲区中“等待”,直到处理器释放以接受更多数据。如果目标从流中接收数据的速度慢于其处理数据的速度,换句话说,如果当前可用的块数量低于处理器可接受的最小数据量,则这些数据块将“等待”缓冲直到有足够数量的数据可用。
缓冲区就是这样:流数据等待的区域,直到数据处理器准备好接受它们为止。无论在何处存在流技术,您都可以期望在后台运行缓冲区来存储尚未处理的数据块。
您可能已经听说过称为缓冲的概念。当您观看YouTube视频时,有时视频会保持加载状态,而不会恢复视频一段时间。这是因为您的浏览器正在等待视频流的更多数据块到达。在浏览器收到足够的数据块之前,它们会存储在这些缓冲区中,并等待处理器接受它们。因此,名称为“缓冲”。这正是Node.js中的二进制流发生的情况。
当我们尝试在Node程序中读取大文件时,也会发生同样的事情。此处使用的缓冲区存储通过文件流发送的数据块,直到有足够的数据可用,然后再将其传递给程序。此过程再次称为缓冲。
5. 但是Node.js如何使用缓冲区?
现在,您了解了缓冲区的基本概念以及为什么需要它们。但是您可能仍然想知道Node为什么需要缓冲区。
好吧,答案很简单。当您将HTTP请求发送到Web服务器时,该请求作为TCP流通过网络发送,该网络是二进制数据流。因此,您构建的所有节点服务器都必须处理流和缓冲区。
当您使用fs.readFile()方法读取文件时,该文件会通过回调或promise返回一个缓冲区对象。
简而言之,Node.js中一些最重要的模块会不断处理缓冲区和缓冲区操作。您可能甚至已经在不知不觉中使用了缓冲区。作为Node开发人员,您还需要什么其他原因来深入学习Node Buffer?
6. Node.js中的缓冲区创建和操作
Node.js提供了一个Buffer类,可让您轻松创建和操作缓冲区。让我们看看我们能用它做什么。
//create a buffer
let buffer1 = Buffer.alloc(100)
这将创建一个大小为100的缓冲区,这意味着该缓冲区存储100个字节的零。
您还可以根据字符串和整数数组创建缓冲区。
let buffer2 = Buffer.from("I'm learning Node Buffer")
//This encodes the given string and stores it as binary data
let buffer3 = Buffer.from([1, 2, 90, 55])
//stores each integer in binary
您可以使用索引访问缓冲区中的每个字节。
buffer2[0] //returns 73 for ‘I’
buffer2.toString() //returns ‘I'm learning Node Buffer’
现在,让我们看看如何写入缓冲区。
buffer2.write("Hi")
buffer2.toString() //returns ‘Hi’
write方法将覆盖缓冲区中的现有内容,并将其更改为您提供的值。
//change the stored value at a given index
buffer2[0] = 80
buffer2.toString() //returns ‘Pi’
//get the buffer length
buffer1.length //returns 100
buffer3.length //returns 4
您可以查看Node.js文档,以了解您还可以使用缓冲区做什么。
8.结论
如您在本文中所见,缓冲区对于Node.js的工作原理至关重要。了解这些概念对于成为更好的Node开发人员至关重要。这些知识可帮助您编写优化的Node程序,并了解该语言的局限性以及如何解决它们。因此,下次您遇到与Node.js相关的令人生畏的术语时,请不要犹豫,像我们使用Buffers一样直接面对它。
https://livecodestream.dev/post/2020-06-06-a-complete-introduction-to-node-buffers/