Node.js躬行记(1)——Buffer、流和EventEmitter
一、Buffer
Buffer是一种Node的内置类型,不需要通过require()函数额外引入。它能读取和写入二进制数据,常用于解析网络数据流、文件等。
1)创建
通过new关键字初始化Buffer对象的方式已经被废弃,下面的代码都已经过时。
new Buffer(array)
new Buffer(arrayBuffer[, byteOffset[, length]])
new Buffer(buffer)
new Buffer(size)
new Buffer(string[, encoding])
目前有两种方式创建Buffer对象,第一种是通过alloc()或allocUnsafe()两个静态方法,语法如下。
Buffer.alloc(size[, fill[, encoding]])
Buffer.allocUnsafe(size)
alloc()方法可接收三个参数,后两个是可选的。第一个参数是长度,第二个参数是预填充的值,第三个参数是字符编码,默认值是“utf8”。
const buf1 = Buffer.alloc(10);
const buf2 = Buffer.alloc(10, "A");
const buf3 = Buffer.alloc(10, "A", "ascii");
如果打印buf3,那么得到的将是一组十六进制数据,而非难以阅读的二进制数据,如下所示。
<Buffer 41 41 41 41 41 41 41 41 41 41>
注意,Buffer的大小在创建时确定,后面也无法更改,其类型可由Buffer.isBuffer()辨别。当前Node支持的字符编码有6种:
(1)ascii:仅适用于7位的ASCII数据。
(2)utf8:多字节编码的Unicode字符。许多网页和其它文档格式都在使用UTF-8。
(3)utf16le/ucs2:2或4个字节,小端序编码的Unicode字符。支持代理对(U+10000至U+10FFFF)。
(4)base64:Base64编码,一种基于64个可打印字符来表示二进制数据的表示方法。
(5)latin1/binary:一种可编码成单字节字符串的方法。
(6)hex:将每个字节编码成两个十六进制的字符。
allocUnsafe()是一个不安全的方法,因为它分配的内存片段是未初始化的,即没有被清零。虽然这种设计性能优越,但分配的内存中可能会包含旧数据。
第二种是通过Buffer.from()方法创建Buffer对象,它的参数可以是数组、字符串、Buffer对象等,如下所示。
const buf = Buffer.from("A");
console.log(buf); //<Buffer 41>
2)转换编码
在读取文件时,可通过toString()方法将Buffer对象转换成字符串,如下所示,默认是UTF-8格式。
const fs = require('fs');
fs.readFile('./demo.txt', (err, buf) => {
buf.toString(); //"你好,Node.js"
buf.toString("base64"); //"5L2g5aW977yMTm9kZS5qcw=="
});
二、流
Node中的stream模块用于处理流式数据,许多内置的核心模块都在其内部实现了流操作,流还适用于网络传输、JSON解析器、RFC(远程调用)等。流包括四个抽象类:
(1)Readable:可读流,读取底层的I/O数据源。
(2)Writeable:可写流,将数据写入到目标中。
(3)Duplex:双工流,即可读也可写。
(4)Transform:转换流,会修改数据的双工流。
1)pipe()
在可读流中,包含一个管道方法:pipe(),它的作用是关联可读流与可写流,让数据通过管道从可读流进入到可写流中。pipe()方法能接收一个Writable对象,并返回对目标流的引用,从而可形成链式调用。
在下面的示例中,会将origin.txt中的数据通过管道写入到target.txt文件中,调用文件模块的createReadStream()方法能得到一个Readable对象。
const fs = require('fs');
const readable = fs.createReadStream('./origin.txt');
const writable = fs.createWriteStream('./target.txt');
readable.pipe(writable);
2)事件
以可读流为例,它的data事件可在接收到数据块后触发,而end事件会在流没有数据时触发。在下面的示例中,origin.txt文件包含的内容是“hello Node.js”。
const fs = require('fs');
const readable = fs.createReadStream('./origin.txt', {highWaterMark: 2});
readable.on("data", (chunk) => {
console.log(`接收到 ${chunk.length} 个字节的数据`, chunk.toString());
});
readable.on("end", () => {
console.log("结束接收");
});
在调用createReadStream()方法时,包含一个highWaterMark属性,其默认值为64KB,它的作用是限制可缓冲的字节数。当定义为2后,每接收2个字节的数据,就会触发data事件,打印结果如下所示。
接收到 2 个字节的数据 he
接收到 2 个字节的数据 ll
接收到 2 个字节的数据 o
接收到 2 个字节的数据 No
接收到 2 个字节的数据 de
接收到 2 个字节的数据 .j
接收到 1 个字节的数据 s
结束接收
可读流还包含一个error事件,用于监听异常,其事件处理程序会接收一个Error对象。在下面的示例中,会读取不存在的文件,从而触发error事件。
const readable = fs.createReadStream('./demo.txt');
readable.on("error", (err) => {
console.log(err); //打印错误信息
});
3)实现流
当实现自定义的流时,需要继承四个抽象类中的一个,表1列出了四个抽象类需要实现的方法。
| 抽象类 | 需要实现的方法 |
| Readable | _read() |
| Writeable | _write()、_writev()、_final() |
| Duplex | _read()、_write()、_writev()、_final() |
| Transform | _transform()、_flush()、_final() |
下面是一个自定义可写流的例子,_write()方法中的encoding是一个字符串,表示字符编码。
const { Writable } = require('stream');
class MyWritable extends Writable {
constructor(options) {
super(options);
}
_write(chunk, encoding, callback) {
if (encoding === "buffer") {
callback();
}
}
}
三、EventEmitter
Node的事件模块目前只包含一个EventEmitter类(即事件触发器),所有能触发事件的对象都是EventEmitter类的实例。EventEmitter通常被用作基类,在Node内部,凡是提供事件机制的模块都会继承它。
在下面的示例中,声明了一个EventEmitter实例,on()方法用于注册监听器,emit()方法用于触发事件。在调用emit()方法时,传递了自定义的type参数。
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('click', (type) => {
console.log(`触发${type}事件`);
});
myEmitter.emit('click', "点击");
注意,可注册多个相同名称的事件,监听器会按照添加顺序依次调用。事件模块还提供了很多其它方法,例如off()用于解除事件绑定,once()可以只监听一次事件。
Node.js躬行记(1)——Buffer、流和EventEmitter的更多相关文章
- Node.js躬行记(2)——文件系统和网络
一.文件系统 fs模块可与文件系统进行交互,封装了常规的POSIX函数.POSIX(Portable Operating System Interface,可移植操作系统接口)是UNIX系统的一个设计 ...
- Node.js躬行记(19)——KOA源码分析(上)
本次分析的KOA版本是2.13.1,它非常轻量,诸如路由.模板等功能默认都不提供,需要自己引入相关的中间件. 源码的目录结构比较简单,主要分为3部分,__tests__,lib和docs,从名称中就可 ...
- Node.js躬行记(4)——自建前端监控系统
这套前端监控系统用到的技术栈是:React+MongoDB+Node.js+Koa2.将性能和错误量化.因为自己平时喜欢吃菠萝,所以就取名叫菠萝系统.其实在很早以前就有这个想法,当时已经实现了前端的参 ...
- Node.js躬行记(6)——自制短链系统
短链顾名思义是一种很短的地址,应用广泛,例如页面中有一张二维码图片,包含的是一个原始地址(如下所示),如果二维码中的链接需要修改,那么就得发代码替换掉. 原始地址:https://github.com ...
- Node.js躬行记(15)——活动规则引擎
在日常的业务开发中,会包含许多的业务规则,一般就是用if-else硬编码的方式实现,这样就会增加逻辑的维护成本,若无注释,可能都无法理解规则意图. 因为一旦规则有所改变,那么就需要修改代码再发布代码, ...
- Node.js躬行记(21)——花10分钟入门Node.js
Node.js 不是一门语言,而是一个基于 V8 引擎的运行时环境,下图是一张架构图. 由图可知,Node.js 底层除了 JavaScript 代码之外,还有大量的 C/C++ 代码. 常说 Nod ...
- Node.js躬行记(23)——Worker threads
Node.js 官方提供了 Cluster 和 Child process 创建子进程,通过 Worker threads 模块创建子线程.但前者无法共享内存,通信必须使用 JSON 格式,有一定的局 ...
- Node.js躬行记(3)——命令行工具
一.自定义 创建一个空目录,然后通过npm init命令初始化package.json文件,并按提示输入相关信息或直接回车使用默认信息,生成的内容如下所示. { "name": & ...
- Node.js躬行记(14)——压力测试
公司有个匿名聊天的常规H5界面,运营向做一次 50W 的推送,为了能配合她的计划,需要对该界面做一次压力测试. 一.JMeter 压测工具选择了JMeter,这是Apache的一个项目,它是用Java ...
随机推荐
- Linux运维面试题:请简要说明Linux系统在目标板上的启动过程?
Linux运维面试题:请简要说明Linux系统在目标板上的启动过程? 该问题是Linux运维面试最常见的问题之一,问题答案如下: 1.用户打开PC的电源,BIOS开机自检,按BIOS中设置的启动设备( ...
- CultureInfo 类中需要的【区域性名称】查询
2019独角兽企业重金招聘Python工程师标准>>> 提供有关特定区域性的信息(对于非托管代码开发,则称为"区域设置"). 这些信息包括区域性的名称.书写系统. ...
- du命令、df命令、磁盘分区
df:汇报文件系统的磁盘使用空间[root@localhost ~]# df文件系统 1K-块 已用 可用 已用% 挂载点/dev/sda3 29140072 1022920 28117152 4% ...
- CS Requirements and Resources
有感于国内令人发指的CS教育,决定以自学为主. 路线会按照计算机科学与技术的技能树,主要学习四大的比较完整的课程,video没时间看,但reading会仔细看.lab会认真做,对于一些比较有意义.代码 ...
- Arduino编程基础1.1
Arduino编程语言是建立在C/C++语言基础上的,即以C/C++语言为基础,把AVR单片机(微控制器)相关的一些寄存器参数设置等进行函数化,以利于开发者更加快速地使用.其主要使用的函数包括数字I/ ...
- python 中open文件路径的选择
一.问题描述 python 中使用open打开某个文件写入时,往往会发现需要写入的文件不在同级目录下.这样就需要根据文件的路径来找到并打开. 但往往有时绝对路径和相对路径,写入不正确就会打开失败. 二 ...
- 解决Vue中文本输入框v-model双向绑定后数据不显示的问题
前言 项目中遇到一个问题就是在Vue中双向绑定对象属性时,手动赋值属性后输入框的数据不实时更新的问题. <FormItem label="地址" prop="eve ...
- 3-MyBatisPlus教程(CRUD-上)
1,增加MP日志配置 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:m ...
- python-圆周率的计算【random库的应用】
圆周率的计算 ...
- 【HBase】协处理器是什么?又能干什么?怎么用?
目录 简单了解 官方帮助文档 协处理器出现的原因 协处理器的分类 Observer Endpoint Phoenix 协处理器的使用 加载方式 静态加载 动态加载 协处理器的卸载 协处理器Observ ...