和Node.js的Buffer说拜拜

声明:(1)此文为译文,原文见 Goodbye, Node.js Buffer (2)翻译不准处的后面加上了英文原文词汇或进行了不影响理解的删减(3)翻译不对的地方请不吝赐教,留言更正(4)为了使文章更具有可读性,译者适当地增加了标题和划分了段落。

Buffer存在的缺欠

Buffer类型从一开始就是Node.js中处理二进制数据的基石。然而,现在我们有了 Uint8Array,这是一个原生的 JavaScript 类型并且可以跨平台工作。而 Buffer 是 Uint8Array 的一个实例,它引入了许多在其他 JavaScript 环境中不可用的方法。因此,那些使用了特定于Buffer的方法(Buffer-specific methods)的相关代码需要进行填充(polyfilling),这阻碍了许多有价值的包和浏览器兼容。

Buffer 还带了一些额外的问题。例如:

第一,Buffer的slice()方法,创建了一个链接到原始缓冲区的可变片段(segment ),会导致一些不可预测的行为,然而 Uint8Array的slice()方法则创建了一个不可变的副本。问题不在于Buffer的slice()方法的行为,而在于Buffer是Uint8Array的子类,它完全改变了继承自Uint8Array的方法的行为。可以使用Unit8Array的subarray()方法或者Buffer的subarray()方法代替Buffer的slice()方法。

第二,Buffer通过全局变量暴露隐私信息,这是一个潜在的安全风险。

我们是时候和Buffer说拜拜了!

我的升级计划

我打算将我所有的包从使用 Buffer 改为Uint8Array。如果您是 JavaScript 包的维护者,我鼓励您也这样做。Buffer可能永远不会被删除,甚至可能永远不会被弃用,但至少社区可以慢慢远离它,我希望 Node.js 团队至少开始不鼓励使用 Buffer。

如何进行升级

首先,熟悉 Uint8Array 和 Buffer 之间微妙的不兼容性。我已经开发了uint8array-extras包来使转换更加容易。

如果你的代码使用了 Buffer 并且没有使用任何特定于 Buffer 的方法( Buffer-specific methods),那么只需将文档和数据类型更新为 Uint8Array 即可。

将输入类型从 Buffer 更改为 Uint8Array 是非破坏性更改,因为 Buffer 是 Uint8Array 的实例。

将返回类型从 Buffer 更改为 Uint8Array 是一个重大更改,因为返回值的消费者可能使用特定于Buffer的方法(Buffer-specific methods)。

如果你确实需要将 Uint8Array 转换为 Buffer,可以使用 Buffer.from (uint8Array)(拷贝数据)或者 Buffer.from(uint8Array.buffer, uint8Array.byteOffset, uint8Array.byteLength)(不拷贝数据)。然而还有更好的方法吗?

一些主要的修改步骤是:

  • 删除所有的import {Buffer} from 'node:buffer' 导入语句
  • 删除所有的Buffer全局变量
  • 停止使用特定于Buffer的方法
  • 替换 Buffer的读/写方法,例如用DataView替换Buffer的readInt32BE()方法

解答一些问题

1.Buffer 为什么一开始会存在?

在 Uint8Array 存在之前很久就已经创建了 Buffer。

2.如何使用 Uint8Array 进行与 Base64之间的转换?

你现在可以使用我的 uint8array-extras 包,它很可能最终会在 原生JavaScript 中得到支持。

3.如何处理返回Buffer的 Node.js API,比如 fs 的方法?

因为 Buffer 是 Uint8Array 的一个子类,所以您可以将它看作 Uint8Array。只要确保不使用. slice ()(它在行为上有所不同)或任何特定于 Buffer 的方法( Buffer-specific methods)。

例子

Javascript代码

JavaScript 复制代码
+ import {stringToBase64} from 'uint8array-extras';

- Buffer.from(string).toString('base64');
+ stringToBase64(string);
JavaScript 复制代码
+ import {uint8ArrayToHex} from 'uint8array-extras';

- buffer.toString('hex');
+ uint8ArrayToHex(uint8Array);
JavaScript 复制代码
const bytes = getBytes();

+ const view = new DataView(bytes.buffer);

- const value = bytes.readInt32BE(1);
+ const value = view.getInt32(1);
JavaScript 复制代码
import crypto from 'node:crypto';
- import {Buffer} from 'node:buffer';
+ import {isUint8Array} from 'uint8array-extras';

 export default function hash(data) {
	- if (!(typeof data === 'string' || Buffer.isBuffer(data))) {
	+ if (!(typeof data === 'string' || isUint8Array(data))) {
 		throw new TypeError('Incorrect type.');
 	}

 	return crypto.createHash('md5').update(data).digest('hex');
 }

大多数 Node.js API 也接受 Uint8Array,因此不需要额外的工作。

TypeScript代码

TypeScript 复制代码
- import {Buffer} from 'node:buffer';

- export function getSize(input: string | Buffer): number { ... }
+ export function getSize(input: string | Uint8Array): number { ... }

强制使用Unit8Array

我建议使用 lint工具(linting)强制使用 Uint8Array 而不是 Buffer,将如下内容增加到你的ESLint配置当中:

JavaScript 复制代码
{
	'no-restricted-globals': [
		'error',
		{
			name: 'Buffer',
			message: 'Use Uint8Array instead.'
		}
	],
	'no-restricted-imports': [
		'error',
		{
			name: 'buffer',
			message: 'Use Uint8Array instead.'
		},
		{
			name: 'node:buffer',
			message: 'Use Uint8Array instead.'
		}
	]
}

如果你使用的是TypeScript则使用如下内容:

TypeScript 复制代码
{
	'@typescript-eslint/ban-types': [
		'error',
		{
			types: {
				Buffer: {
					message: 'Use Uint8Array instead.',
					suggest: [
						'Uint8Array'
					]
				}
			}
		}
	]
}
相关推荐
We་ct2 小时前
LeetCode 77. 组合:DFS回溯+剪枝,高效求解组合问题
开发语言·前端·算法·leetcode·typescript·深度优先·剪枝
KerwinChou_CN3 小时前
什么是流式输出,后端怎么生成,前端怎么渲染
前端
爱上妖精的尾巴3 小时前
8-18 WPS JS宏 正则表达式-边界匹配
开发语言·javascript·正则表达式·wps·jsa
爱上妖精的尾巴3 小时前
8-20 WPS JS宏 正则表达式-懒惰匹配
服务器·前端·javascript
网络点点滴3 小时前
组件通信props方式
前端·javascript·vue.js
二十雨辰3 小时前
[小结]-线上Bug监控
前端·bug
前端技术3 小时前
【鸿蒙实战】从零打造智能物联网家居控制系统:HarmonyOS Next分布式能力的完美诠释
java·前端·人工智能·分布式·物联网·前端框架·harmonyos
CHU7290353 小时前
指尖践行环保——旧衣服回收小程序前端功能玩法详解
前端·小程序
weixin_443478513 小时前
flutter组件学习之Flex / Expanded弹性布局组件
javascript·学习·flutter
LawrenceLan3 小时前
38.Flutter 零基础入门(三十八):网络请求实战 http、dio —— 获取列表与刷新 UI
开发语言·前端·flutter·dart