Node Buffers 完整指南

发布于:2020 年 6 月 18 日 18:34

Node Buffers 完整指南

身为 Node 开发人员这些年来,你是否从未遇到过 Node 缓冲区(Buffer)这个概念呢?也许这个术语你见过几次,但每次都不想一探究竟?你可能的确没遇到过要使用缓冲区的场景,毕竟 Node.js 并不是那种要求程序员直接和程序管理内存的操作打交道的语言。但是,如果你想要成为专业 Node 开发人员,愿意为此付出更多的努力,那么你就必须深入探索缓冲区之类的概念,从而理解 Node 的底层工作机制。

本文最初发布于 livecodestram.dev 网站,经网站授权由 InfoQ 中文站翻译并分享。

初看上去,你会觉得 Node 缓冲区是一个很难理解的主题,但事实并非如此。问题在于你看过的所有在线教程上来就会创建一些 Node 缓冲区,然后开始操作它们,却没有提前解释到底这是什么东西。为了避免在这篇文章中犯同样的错误,我会首先解释什么是缓冲区。但在此之前,我们必须搞明白伴随缓冲区出现的其他一些概念。

为了正确理解缓冲区,我们应该了解二进制数据、字符编码(character encoding)和流(stream)。你可能还不明白它们和缓冲区有什么关系,先别急,搞懂它们后就能知道缓冲区是什么意思了。

什么是二进制数据?

如果你已经知道了什么是二进制数据,则可以直接跳到下一个主题。否则就请读下去,了解什么是二进制数据。

二进制数字系统是类似我们常用的十进制的另一个数字系统。十进制使用 0-9 的数表示数字,而二进制仅使用 0 和 1 表示数字。下面是二进制数的一些示例。

复制代码
0, 1, 10, 101, 1011011, 1000101

在计算机科学中,二进制数中的每个数字均被视为一个。8 个位合称一个字节。那么计算机科学与二进制有什么关系?计算机使用二进制数字来存储和表示数据。因此,存储在计算机中的每种数据最终都将存储为一组二进制数。我们称这些数据为二进制数据。
为了将所有类型的数据都存储为二进制数据,计算机应该知道如何将它们转换为二进制数。计算机为实现这一目的有很多种机制,下面具体介绍。

计算机如何将数字转换为二进制数据?

将数字转换为二进制数据只是一种数学处理。十进制数字 9 可以用二进制表示为 101,其他整数也有自己的对应。计算机具备自行做这种转换的能力。

计算机如何将字符转换为二进制数据?

对这个问题的简单解释是“每个字符都有一个与之关联的唯一二进制数”。这种唯一编号称为字符的代码点字符码。你可以在 Javascript 中使用 charCodeAt 函数来查找每个字符的字符码。

复制代码
'a'.charCodeAt() //outputs 97
'A'.charCodeAt() //outputs 65

有两大标准用来为每个字符分配字符码:ASCII 和 Unicode。无论使用哪种编程语言,它们各自赋予字符的字符码都是一样的。ASCII 最多使用 7 位来表示字符,而 Unicode 最多使用 16 位。所以 Unicode 提供了比 ASCII 更大的范围,可以表示更多的字符,进而成为了最受欢迎的标准。
计算机将字符转换为二进制数据时,需要做的唯一工作就是查找每个字符的字符点吗?答案是否定的。你还需要执行一个将字符转换为二进制数据的步骤。那就是字符编码。

什么是字符编码?

我之前提到过 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。

这样就完成了将字符转换为二进制数据的过程。将字符串转换为二进制数据时,无非就是将每个字符都转换为二进制数据。计算机将图像、音频和视频数据转换为二进制数据时会用到更多的标准和方法。

现在出现了的概念。我们来看看它又是什么。

什么是流?

流是从一处移到另一处的数据的集合。这里我们谈论的是二进制数据流,它是从一个地方移动到另一个地方的二进制数据的集合。

一条流中会包含大量数据。但是计算机不必等待流中的所有数据到位也可以开始处理它们。将流发送到某个目的地时,由于数据太多了,因此不会一次发送完流中的全部数据,而是将流分为许多较小的数据块。目标会接收这些块并归拢起来,并在有足够的块可用时开始处理它们。

接收流的目标会以某种方式处理数据——可以是读取、操作或写入数据。但是目标处的数据处理器的能力,限制了它一次可以处理的数据量的上下限。那么,当目标接收到不符合此限制的数据块时会发生什么呢?目标无法丢弃它们。然而,目标可以使用一种机制来存储接收到的块,直到它们可以被处理器处理为止。这里就引入了缓冲区的概念。但首先我们应该知道缓冲区到底是什么,才能进一步理解它们如何帮助存储数据块。

什么是缓冲区,它们要做什么?

一个缓冲区是计算机内存(通常是 RAM)中一处较小的存储空间。在目标处理器准备好处理来自流的数据块之前,缓冲区充当后者的等待区域。

如果目标从流中接收数据的速度快于其处理数据的速度,则这些多余的数据将在缓冲区中“等待”,直到处理器可以处理新的数据为止。如果目标从流中接收数据的速度慢于其处理数据的速度,换句话说,如果当前可用的块数量低于处理器可接受的最小数据量,则这些数据块将在一个缓冲区中“等待”,直到有足够数量的数据可用为止。

所以缓冲区指的就是一处等待区域,流数据在这里等待处理器,直到后者准备好处理数据为止。只要是有流存在的地方,你都会看到后台存在缓冲区来存储尚未处理的数据块。

你可能已经听说过缓冲(buffering)这个概念。当你观看 YouTube 视频时,有时视频会加载一段时间,然后才会继续播放。这是因为你的浏览器正在等待视频流的更多数据块就位。在浏览器收到足够的数据块之前,它们会存储在这些缓冲区中,并等待处理器处理。这就是“缓冲”这个名词的来历。这也正是 Node.js 中二进制流会遇到的情况。

当我们尝试在 Node 程序中读取大文件时,也会发生同样的事情。这里使用的缓冲区会存储通过文件流发送的数据块,直到有足够的数据可用,然后再将其传递给程序。此过程也称为缓冲。

但是 Node.js 如何使用缓冲区?

现在,你已经了解了缓冲区的基本概念以及为什么需要它们。但是你可能还想知道 Node 为什么需要缓冲区。

答案很简单。当你将 HTTP 请求发送到 Web 服务器时,该请求会作为 TCP 流通过网络发送,这是一个二进制数据流。因此,你构建的所有 Node 服务器都必须处理流和缓冲区。

当你使用 fs.readFile() 方法读取文件时,它将通过回调或 promise 返回一个缓冲区对象。

简而言之,Node.js 中一些最重要的模块会不断处理缓冲区和缓冲区操作。你可能已经在不知不觉中用过了缓冲区。

Node.js 中的缓冲区创建和操作

Node.js 提供了一个 Buffer 类,可让你轻松创建和操作缓冲区。我们来看看用它能做什么。

复制代码
// 创建一个 buffer
let buffer1 = Buffer.alloc(100)

这将创建一个大小为 100 的缓冲区,这意味着该缓冲区会存储 100 个字节的零。
你还可以从字符串和整数数组创建缓冲区。

复制代码
let buffer2 = Buffer.from("I'm learning Node Buffer")
// 编码给定字符串并将其存储为二进制数据
let buffer3 = Buffer.from([1, 2, 90, 55])
// 将每个整数存储为缓冲区

你可以使用索引访问缓冲区中的每个字节。

复制代码
buffer2[0] //returns 73 for ‘I’
buffer2.toString() //returns ‘I'm learning Node Buffer’

现在我们来看看如何写入缓冲区。

复制代码
buffer2.write("Hi")
buffer2.toString() //returns ‘Hi’

write 方法将覆盖缓冲区中的现有内容,并将其更改为你提供的值。

复制代码
// 使用指定的索引更改存储的值
buffer2[0] = 80
buffer2.toString() //returns ‘Pi’
// 获取缓冲区长度
buffer1.length //returns 100
buffer3.length //returns 4

你可以查看 Node.js 文档( https://nodejs.org/api/buffer.html ),了解还可以使用缓冲区做些什么事情。

小结

如你在本文中所见,缓冲区对于 Node.js 的工作机制而言至关重要。了解这些概念可以帮助你成为更优秀的 Node 开发人员。这些知识可帮助你编写优化的 Node 程序,并了解这种语言的局限性,知道如何解决它们。因此,下次你遇到与 Node.js 相关的令人生畏的术语时,请不要犹豫,应该像对待缓冲区一样直接面对它。

原文链接: https://livecodestream.dev/post/2020-06-06-a-complete-introduction-to-node-buffers

阅读数:3 发布于:2020 年 6 月 18 日 18:34

评论

发布
暂无评论