Docker 常用命令

精简 Docker 常用命令

2022-11-06 · 1 min read

项目管理

项目管理相关知识

2022-11-06 · 1 min read

JS沙箱sandbox的各种实现

我们把Js隔离机制常常称作沙箱

2022-09-18 · 1 min read

Amazing!Solid 比react还react

今天来介绍2个amazing的东东

2022-09-12 · 1 min read

puppeteer应用

使用傀儡师来操作浏览器这个傀儡吧

2022-09-11 · 1 min read

做一个web termianl

前端react, 后端nodejs, 直接可用版web termianl

2022-07-17 · 1 min read

TypeScript里常用的工具类型

经常用到的工具类型,提取抽离出来,供以后复用

2022-06-26 · 1 min read

Vim大法好

想要丢掉鼠标,试试Vim

2022-06-26 · 1 min read

碧血丹心

无论时光如何沾染风霜,也永似红日光

2022-05-10 · 1 min read

chrome V8 引擎中的垃圾回收机制

V8引擎就是nodejs的发动机

2022-03-03 · 1 min read

如何开发一个cli

命令行交互界面是程序员必备的工具,如何开发一个呢?

2022-02-21 · 1 min read

Javascript中的哲学

道生一,一生二,二生三,三生万物

2022-02-20 · 1 min read

React Redux 实现 (Context 版)

React Redux 实现 (Context 版)

2022-02-16 · 1 min read

mobx-react 使用

虽然不常用,但是可以学一下

2022-02-16 · 1 min read

Less中的for和forEach循环

循环的使用是保持代码干燥和避免重复的好方法

2022-02-15 · 1 min read

Webpack Splitchunks 详解

webpack 优化

2022-02-15 · 1 min read

ssh-keygen命令详解

为ssh生成、管理和转换认证密钥

2022-02-15 · 1 min read

使用CURL发送POST请求

curl 是常用的命令行工具,用来请求 Web 服务器。

2022-02-15 · 1 min read

Webpack Plugin 开发

让我们来学一下如何开发一个webpack插件

2022-02-14 · 1 min read

JS 实现两个大数相加?

algo-adding-large-numbers

2022-02-10 · 1 min read

字典树 trie

字典树 trie

2022-02-09 · 1 min read

浏览器原理问题

浏览器原理问题

2022-01-11 · 1 min read

MacBook快速进入一个文件夹目录

mac如何快速进入一个文件夹

2021-10-26 · 1 min read

react合成事件

react-synthetic-event

2021-10-25 · 1 min read

mini webpack实现

通过babel核心来实现迷你版的webpack

2021-10-10 · 1 min read

设计模式

在程序设计中有很多实用的设计模式,而其中大部分语言的实现都是基于类

2021-10-10 · 1 min read

babel核心

babel核心介绍

2021-10-07 · 1 min read

React 15 和 React 16 的区别

react-15-16

2021-10-06 · 1 min read

React性能优化

浅谈react性能优化的方法

2021-10-05 · 1 min read

交通信号灯实现

如何用js来实现交通信号灯呢

2021-09-25 · 1 min read

内存管理

前端中的内存管理

2021-09-25 · 1 min read

前端安全

前端关于安全方面的知识

2021-09-25 · 2 min read

网络和并发

http各版本对于并发的支持,前端如何控制并发量?

2021-09-25 · 1 min read

跨域方法

总结了9种跨域方法

2021-09-24 · 1 min read

react virtualList 虚拟列表无限滚动实现

用react实现虚拟滚动

2021-09-16 · 1 min read

监控埋点方案

前端监控埋点方案

2021-09-16 · 1 min read

Mini useEffect实现

如何实现useEffect?

2021-09-11 · 1 min read

Mini useState 实现

我们来思考一下useState是怎么实现的呢?

2021-09-11 · 1 min read

React Fiber

react-fiber

2021-09-11 · 1 min read

React class组件和function组件异同

类组件和函数组件有何相同点有何不同点呢?

2021-09-11 · 1 min read

Lodash Get 实现

algo-lodash-get

2021-09-08 · 1 min read

手写reduce实现

algo-reduce

2021-09-08 · 1 min read

Hooks 原理概览

react-hooks

2021-09-05 · 1 min read

Hook原理——状态Hook

react-hook-state

2021-09-05 · 1 min read

手写Mini Redux实现

手写一个简易版的redux实现,包含了核心逻辑

2021-09-04 · 1 min read

legacy和concurrent模式

react-legacy-concurrent

2021-09-01 · 1 min read

react架构

总体 react 的核心可以用 ui=fn(state)来表示 3 大核心对象、3 大核心阶段、2 大工作循环 Scheduler(调度器): 排序优先级,让优先级高的任务先进行 reconcile Reconciler…

2021-09-01 · 2 min read

react核心api和jsx

为什么要有jsx,为什么会有虚拟bom

2021-09-01 · 1 min read

setState是同步的还是异步的

react-setstate-usestate

2021-08-31 · 1 min read

如何使用NodeJs创建HTTP服务?

如何使用NodeJs创建HTTP服务?

2021-08-17 · 1 min read

NodeJS 事件循环模型

nodejs-eventloop

2021-08-11 · 2 min read

Buffer

nodejs中的内存管理

2021-08-10 · 1 min read

微前端解决方案-qiankun

目前国内最好的微前端解决方案-qiankun

2021-08-10 · 1 min read

React Mini版实现(1)

学一门技术最好的方法就是做一个其玩具版的实现,我们来尝试实现一下react和react-dom最简单版本吧

2021-08-04 · 1 min read

brew安装

brew 是 MacOS 上的包管理工具,可以简化 macOS 和 Linux 操作系统上软件的安装。

2021-08-04 · 1 min read

CommonJS简易版实现

CommonJS我们经常用,如何实现一个简易版的commonJS呢?

2021-08-01 · 1 min read

极品透明Dashboard样式分享

一个极品透明Dashboard样式分享

2021-07-30 · 1 min read

Stream

nodejs中的流

2021-07-11 · 1 min read

NodeJS全局对象

JavaScript 中有一个特殊的对象,称为全局对象(Global Object),它及其所有属性都可以在程序的任何地方访问,即全局变量。

2021-05-18 · 1 min read

如何部署Nodejs服务

如何快速的部署一个Nodejs服务到公网呢?

2021-05-12 · 1 min read

Events

events模块是node的核心模块之一,几乎所有常用的node模块都继承了events模块,比如http、fs等。

2021-05-11 · 1 min read

用JS绘制背景,让CSS直接使用 'background:paint(xxx)'

CSS对象新特性,新的background设置方式

2021-04-30 · 1 min read

如何使用Nodejs来创建一个TCP/UDP服务?

如何使用Nodejs来创建一个TCP/UDP服务?

2021-04-17 · 1 min read

Mac使用tree生成目录结构

程序员经常会有需求,需要列出项目的结构树。Mac或者Linux下可以使用tree列出项目结构

2021-04-04 · 1 min read

常见算法

一些比较常见算法

2021-03-20 · 1 min read

前端缓存

对于性能优化离不开缓存

2021-02-28 · 1 min read

前端答疑

一些比较常见的问题

2020-09-02 · 1 min read

Nodejs 网络 & HTTP

nodejs-network

2020-08-14 · 1 min read

JavaScript AST 抽象语法树

源代码的抽象语法结构的树状表现形式

2020-08-02 · 1 min read

nodejs里面向切面编程的一种范式

在一些场景下我们可能需要一种面向切面的编程方式

2020-08-01 · 1 min read

各种JS模块化特性

AMD、CMD、CJS、ESM

2020-05-30 · 1 min read

手写Ajax实现

使用HMR一步步实现Ajax

2020-05-30 · min read

手写PromiseA+实现

如何自己实现promiseA+规范,手写一个promise实现

2020-04-30 · 1 min read

debug和内存泄露

nodejs的debug方法

2020-04-08 · 1 min read

Javascript prototype 原型链

js-prototype

2019-09-07 · 1 min read

this指针、作用域

this是在执行时动态读取上下文决定的,不是在定义时决定

2019-06-14 · 1 min read

call、apply、bind的极简实现

使用symbol实

2019-06-03 · 1 min read

CSS联合选择器区分列表元素个数不同所要求的不同样式

对于列表,在有些时候针对于不同个数的item会有不同的显示,比如col份数,用js固然可以,是否可以用css更简便的实现呢?

2019-04-30 · 1 min read

TypeScript基础

介绍TypeScript基础知识

2019-04-30 · 1 min read

JS中的变量提升

为什么js当时要这样设计

2019-03-07 · 1 min read

ES6之Class

关于ES6里的class, 我们有什么不知道的事?

2019-03-01 · 1 min read

HTTP详解

HTTP协议(HyperText Transfer Protocol,超文本传输协议)是用于从WWW服务器传输超文本到本地浏览器的传输协议

2019-02-17 · 2 min read

极简代码实现节流Throttle和防抖Debounce

使用各9行代码实现节流和防抖函数

2019-01-30 · 1 min read

Javascript 事件循环 EventLoop

js-eventloop

2018-09-07 · 1 min read

POST和GET区别

POST和GET区别是什么呢?

2018-08-14 · 1 min read

正则表达式

正则表达式一锅端

2018-07-30 · 1 min read

cloneDeep 深克隆实现

algo-clonedeep

2017-09-07 · 1 min read

webpack

engin-webpack

2017-09-07 · 1 min read

http1.1和http2.0有什么区别

http1.1和http2.0有什么区别

2017-06-14 · 1 min read

手写EventEmitter事件巴士

咱们来手写实现一个EventEmitter事件巴士

2017-01-10 · 1 min read

OOP 面向对象编程

对象是什么?为什么要面向对象?

2016-05-08 · 1 min read
Stay hungry & Stay foolish
战歌
16
The Reluctant Warrior
Immediate Music
To Glory
Two Steps From Hell
Victory
Two Steps From Hell
Empire of Angels
Thomas Bergersen
Serenata Immortale
Immediate Music
Cornfield Chase
Hans Zimmer
Tennessee
Hans Zimmer
He's a Pirate
Martin Ermen
Rise
Hans Zimmer
On Thin Ice
Hans Zimmer
Angels Will Rise
Twisted Jukebo
When It All Falls Down
Audiomachine
Icarus
Ivan Torrent
Star Sky - Instrumental
Two Steps From Hell
亡灵序曲
L
Up Is Down
Hans Zimm
回到首页

Buffer

袁官东
August 10th, 2021 · 1 min read
图:Nguyen Nhut

背景知识

  1. ArrayBuffer

ArrayBuffer 对象用来表示通用的、固定长度的原始二进制数据缓冲区。 ArrayBuffer 不能直接操作,而是要通过类型数组对象 或 DataView 对象来操作,它们会将缓冲区中的数据表示为特定的格式,并通过这些格式来读写缓冲区的内容。

你可以把它理解为一块内存, 具体存什么需要其他的声明。

1new ArrayBuffer(length)
2
3// 参数:length 表示要创建的 ArrayBuffer 的大小,单位为字节。
4// 返回值:一个指定大小的 ArrayBuffer 对象,其内容被初始化为 0。
5// 异常:如果 length 大于 Number.MAX_SAFE_INTEGER(>= 2 ** 53)或为负数,则抛出一个 RangeError 异常。

ex. 比如这段代码, 可以执行一下看看输出什么

1var buffer = new ArrayBuffer(8);
2var view = new Int16Array(buffer);
3
4console.log(buffer);
5console.log(view);
  1. Unit8Array

Uint8Array 数组类型表示一个 8 位无符号整型数组,创建时内容被初始化为 0。 创建完后,可以以对象的方式或使用数组下标索引的方式引用数组中的元素。

1// 来自长度
2var uint8 = new Uint8Array(2);
3uint8[0] = 42;
4console.log(uint8[0]); // 42
5console.log(uint8.length); // 2
6console.log(uint8.BYTES_PER_ELEMENT); // 1
7
8// 来自数组
9var arr = new Uint8Array([21,31]);
10console.log(arr[1]); // 31
11
12// 来自另一个 TypedArray
13var x = new Uint8Array([21, 31]);
14var y = new Uint8Array(x);
15console.log(y[0]); // 21
  1. ArrayBuffer 和 TypedArray的关系

TypedArray: Unit8Array, Int32Array这些都是TypedArray, 那些 Uint32Array 也好,Int16Array 也好,都是给 ArrayBuffer 提供了一个 “View”,MDN上的原话叫做 “Multiple views on the same data”,对它们进行下标读写,最终都会反应到它所建立在的 ArrayBuffer 之上。

ArrayBuffer 本身只是一个 0 和 1 存放在一行里面的一个集合,ArrayBuffer 不知道第一个和第二个元素在数组中该如何分配。

array buffer

为了能提供上下文,我们需要将其封装在一个叫做 View 的东西里面。这些在数据上的 View 可以被添加进确定类型的数组,而且我们有很多种确定类型的数据可以使用。

3.1 例如,你可以使用一个 Int8 的确定类型数组来分离存放 8 位二进制字节。

int8 array

3.2 例如,你可以使用一个无符号的 Int16 数组来分离存放 16 位二进制字节。

array

(是不是和8分音符和16分音符有异曲同工之妙?)

  1. 总结

总之, ArrayBuffer 基本上扮演了一个原生内存的角色.

NodeJs Buffer

Buffer 类以一种更优化、更适合 Node.js 用例的方式实现了 Uint8Array API.

Buffer 类的实例类似于整数数组,但 Buffer 的大小是固定的、且在 V8 堆外分配物理内存。 Buffer 的大小在被创建时确定,且无法调整。

基本使用

1// 创建一个长度为 10、且用 0 填充的 Buffer。
2const buf1 = Buffer.alloc(10);
3
4// 创建一个长度为 10、且用 0x1 填充的 Buffer。
5const buf2 = Buffer.alloc(10, 1);
6
7// 创建一个长度为 10、且未初始化的 Buffer。
8// 这个方法比调用 Buffer.alloc() 更快,
9// 但返回的 Buffer 实例可能包含旧数据,
10// 因此需要使用 fill() 或 write() 重写。
11const buf3 = Buffer.allocUnsafe(10);
12
13// 创建一个包含 [0x1, 0x2, 0x3] 的 Buffer。
14const buf4 = Buffer.from([1, 2, 3]);
15
16// 创建一个包含 UTF-8 字节 的 Buffer。
17const buf5 = Buffer.from('tést');

tips

  1. 当调用 Buffer.allocUnsafe() 时,被分配的内存段是未初始化的(没有用 0 填充)。

虽然这样的设计使得内存的分配非常快,但已分配的内存段可能包含潜在的敏感旧数据。 使用通过 Buffer.allocUnsafe() 创建的没有被完全重写内存的 Buffer ,在 Buffer内存可读的情况下,可能泄露它的旧数据。 虽然使用 Buffer.allocUnsafe() 有明显的性能优势,但必须额外小心,以避免给应用程序引入安全漏洞。

Buffer 与字符编码

Buffer 实例一般用于表示编码字符的序列,比如 UTF-8 、 UCS2 、 Base64 、或十六进制编码的数据。 通过使用显式的字符编码,就可以在 Buffer 实例与普通的 JavaScript 字符串之间进行相互转换。

1const buf = Buffer.from('hello world', 'ascii');
2
3console.log(buf)
4
5// 输出 68656c6c6f20776f726c64
6console.log(buf.toString('hex'));
7
8// 输出 aGVsbG8gd29ybGQ=
9console.log(buf.toString('base64'));

Node.js 目前支持的字符编码包括:

  1. ascii - 仅支持 7 位 ASCII 数据。如果设置去掉高位的话,这种编码是非常快的。
  2. utf8 - 多字节编码的 Unicode 字符。许多网页和其他文档格式都使用 UTF-8 。
  3. utf16le - 2 或 4 个字节,小字节序编码的 Unicode 字符。支持代理对(U+10000 至 U+10FFFF)。
  4. ucs2 - ‘utf16le’ 的别名。
  5. base64 - Base64 编码。当从字符串创建 Buffer 时,按照 RFC4648 第 5 章的规定,这种编码也将正确地接受 “URL 与文件名安全字母表”。
  6. latin1 - 一种把 Buffer 编码成一字节编码的字符串的方式(由 IANA 定义在 RFC1345 第 63 页,用作 Latin-1 补充块与 C0/C1 控制码)。
  7. binary - ‘latin1’ 的别名。
  8. hex - 将每个字节编码为两个十六进制字符。

Buffer 内存管理

在介绍 Buffer 内存管理之前,我们要先来介绍一下 Buffer 内部的 8K 内存池。

8K 内存池

  1. 在 Node.js 应用程序启动时,为了方便地、高效地使用 Buffer,会创建一个大小为 8K 的内存池。
1Buffer.poolSize = 8 * 1024; // 8K
2var poolSize, poolOffset, allocPool;
3
4// 创建内存池
5function createPool() {
6 poolSize = Buffer.poolSize;
7 allocPool = createUnsafeArrayBuffer(poolSize);
8 poolOffset = 0;
9}
10
11createPool();
  1. 在 createPool() 函数中,通过调用 createUnsafeArrayBuffer() 函数来创建 poolSize(即8K)的 ArrayBuffer 对象。createUnsafeArrayBuffer() 函数的实现如下:
1function createUnsafeArrayBuffer(size) {
2 zeroFill[0] = 0;
3 try {
4 return new ArrayBuffer(size); // 创建指定size大小的ArrayBuffer对象,其内容被初始化为0。
5 } finally {
6 zeroFill[0] = 1;
7 }
8}

这里你只需知道 Node.js 应用程序启动时,内部有个 8K 的内存池即可。

  1. 那接下来我们要介绍哪个对象呢?在前面的预备知识部分,我们简单介绍了 ArrayBuffer 和 Unit8Array 相关的基础知识,而 ArrayBuffer 的应用在 8K 的内存池部分的已经介绍过了。那接下来当然要轮到 Unit8Array 了,我们再来回顾一下它的语法:
1Uint8Array(length);
2Uint8Array(typedArray);
3Uint8Array(object);
4Uint8Array(buffer [, byteOffset [, length]]);

其实除了 Buffer 类外,还有一个 FastBuffer 类,该类的声明如下:

1class FastBuffer extends Uint8Array {
2 constructor(arg1, arg2, arg3) {
3 super(arg1, arg2, arg3);
4 }
5}

是不是知道 Uint8Array 用在哪里了,在 FastBuffer 类的构造函数中,通过调用 Uint8Array(buffer [, byteOffset [, length]]) 来创建 Uint8Array 对象。

  1. 那么现在问题来了,FastBuffer 有什么用?它和 Buffer 类有什么关系?带着这两个问题,我们先来一起分析下面的简单示例:
1const buf = Buffer.from('semlinker');
2console.log(buf); // <Buffer 73 65 6d 6c 69 6e 6b 65 72>

为什么输出了一串数字, 我们创建的字符串呢? 来看一下源码

1/**
2 * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError
3 * if value is a number.
4 * Buffer.from(str[, encoding])
5 * Buffer.from(array)
6 * Buffer.from(buffer)
7 * Buffer.from(arrayBuffer[, byteOffset[, length]])
8 **/
9Buffer.from = function from(value, encodingOrOffset, length) {
10 if (typeof value === "string") return fromString(value, encodingOrOffset);
11 // 处理其它数据类型,省略异常处理等其它代码
12 if (isAnyArrayBuffer(value))
13 return fromArrayBuffer(value, encodingOrOffset, length);
14 var b = fromObject(value);
15};

可以看出 Buffer.from() 工厂函数,支持基于多种数据类型(string、array、buffer 等)创建 Buffer 对象。对于字符串类型的数据,内部调用 fromString(value, encodingOrOffset) 方法来创建 Buffer 对象。

是时候来会一会 fromString() 方法了,它内部实现如下:

1function fromString(string, encoding) {
2 var length;
3 if (typeof encoding !== "string" || encoding.length === 0) {
4 if (string.length === 0) return new FastBuffer();
5 // 若未设置编码,则默认使用utf8编码。
6 encoding = "utf8";
7 // 使用 buffer binding 提供的方法计算string的长度
8 length = byteLengthUtf8(string);
9 } else {
10 // 基于指定的 encoding 计算string的长度
11 length = byteLength(string, encoding, true);
12 if (length === -1)
13 throw new errors.TypeError("ERR_UNKNOWN_ENCODING", encoding);
14 if (string.length === 0) return new FastBuffer();
15 }
16
17 // 当字符串所需字节数大于4KB,则直接进行内存分配
18 if (length >= Buffer.poolSize >>> 1)
19 // 使用 buffer binding 提供的方法,创建buffer对象
20 return createFromString(string, encoding);
21
22 // 当剩余的空间小于所需的字节长度,则先重新申请8K内存
23 if (length > poolSize - poolOffset)
24 // allocPool = createUnsafeArrayBuffer(8K); poolOffset = 0;
25 createPool();
26 // 创建 FastBuffer 对象,并写入数据。
27 var b = new FastBuffer(allocPool, poolOffset, length);
28 const actual = b.write(string, encoding);
29 if (actual !== length) {
30 // byteLength() may overestimate. That's a rare case, though.
31 b = new FastBuffer(allocPool, poolOffset, actual);
32 }
33 // 更新pool的偏移
34 poolOffset += actual;
35 alignPool();
36 return b;

所以我们得到这样的结论

  1. 当未设置编码的时候,默认使用 utf8 编码;
  2. 当字符串所需字节数大于4KB,则直接进行内存分配;
  3. 当字符串所需字节数小于4KB,但超过预分配的 8K 内存池的剩余空间,则重新申请 8K 的内存池;
  4. 调用 new FastBuffer(allocPool, poolOffset, length) 创建 FastBuffer 对象,进行数据存储,数据成功保存后,会进行长度校验、更新 poolOffset 偏移量和字节对齐等操作。

More articles from Favori 重剑

微前端解决方案-qiankun

目前国内最好的微前端解决方案-qiankun

August 10th, 2021 · 1 min read

React Mini版实现(1)

学一门技术最好的方法就是做一个其玩具版的实现,我们来尝试实现一下react和react-dom最简单版本吧

August 4th, 2021 · 1 min read
© 2016–2022 Favori 重剑
Link to $https://github.com/yuanguandongLink to $https://favori.zcool.com.cn/Link to $https://codepen.io/favori