一、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的更多相关文章

  1. Node.js躬行记(2)——文件系统和网络

    一.文件系统 fs模块可与文件系统进行交互,封装了常规的POSIX函数.POSIX(Portable Operating System Interface,可移植操作系统接口)是UNIX系统的一个设计 ...

  2. Node.js躬行记(19)——KOA源码分析(上)

    本次分析的KOA版本是2.13.1,它非常轻量,诸如路由.模板等功能默认都不提供,需要自己引入相关的中间件. 源码的目录结构比较简单,主要分为3部分,__tests__,lib和docs,从名称中就可 ...

  3. Node.js躬行记(4)——自建前端监控系统

    这套前端监控系统用到的技术栈是:React+MongoDB+Node.js+Koa2.将性能和错误量化.因为自己平时喜欢吃菠萝,所以就取名叫菠萝系统.其实在很早以前就有这个想法,当时已经实现了前端的参 ...

  4. Node.js躬行记(6)——自制短链系统

    短链顾名思义是一种很短的地址,应用广泛,例如页面中有一张二维码图片,包含的是一个原始地址(如下所示),如果二维码中的链接需要修改,那么就得发代码替换掉. 原始地址:https://github.com ...

  5. Node.js躬行记(15)——活动规则引擎

    在日常的业务开发中,会包含许多的业务规则,一般就是用if-else硬编码的方式实现,这样就会增加逻辑的维护成本,若无注释,可能都无法理解规则意图. 因为一旦规则有所改变,那么就需要修改代码再发布代码, ...

  6. Node.js躬行记(21)——花10分钟入门Node.js

    Node.js 不是一门语言,而是一个基于 V8 引擎的运行时环境,下图是一张架构图. 由图可知,Node.js 底层除了 JavaScript 代码之外,还有大量的 C/C++ 代码. 常说 Nod ...

  7. Node.js躬行记(23)——Worker threads

    Node.js 官方提供了 Cluster 和 Child process 创建子进程,通过 Worker threads 模块创建子线程.但前者无法共享内存,通信必须使用 JSON 格式,有一定的局 ...

  8. Node.js躬行记(3)——命令行工具

    一.自定义 创建一个空目录,然后通过npm init命令初始化package.json文件,并按提示输入相关信息或直接回车使用默认信息,生成的内容如下所示. { "name": & ...

  9. Node.js躬行记(14)——压力测试

    公司有个匿名聊天的常规H5界面,运营向做一次 50W 的推送,为了能配合她的计划,需要对该界面做一次压力测试. 一.JMeter 压测工具选择了JMeter,这是Apache的一个项目,它是用Java ...

随机推荐

  1. HDU1873 看病要排队【模拟+优先队列】

    看病要排队 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Subm ...

  2. 数学--数论--POJ1365——Prime Land

    Description Everybody in the Prime Land is using a prime base number system. In this system, each po ...

  3. POJ - 2387 Til the Cows Come Home (最短路入门)

    Bessie is out in the field and wants to get back to the barn to get as much sleep as possible before ...

  4. 【Elasticsearch学习】之基础概念

    Elasticsearch是一个近实时的分布式搜索引起,其底层基于开源全文搜索库Lucene:Elasticsearch对Lucene进行分装,对外提供REST API 的操作接口.基于 ES,可以快 ...

  5. C#基础之接口(6)

    接口的定义:interface. 什么是接口? 接口,我的理解是接口是一种规范.就好比,一个生产数据线的厂商有很多,形状,外观都不一样,现在制定了一个规范那就是所有的数据线生产商都必须把产品外观形状都 ...

  6. 1) drf 整体了解

    一.接口 """ 1.什么是接口:url+请求参数+响应数据 | 接口文档 ​ 2.接口规范: url:https,api,资源(名词复数),v1,get|post表示操 ...

  7. eclipse手动添加SVN插件

    最近使用eclipse时,用help下自动下载更新svn总是出错,网上找到手动安装方法,记录下一种可行的 1.手动下载svn插件(百度SVNsite-1.8.18) 2.将下载好的SVNsite-1. ...

  8. redis-py中的坑

    今天发现,使用redis-py从redis中获取的数据竟然是加密的. conn = redis.Redis(host='redis_serverip', port=6379, password='re ...

  9. 你知道Spring是怎么解析配置类的吗?

    彻底读懂Spring(二)你知道Spring是怎么解析配置类的吗? 推荐阅读: Spring官网阅读系列 彻底读懂Spring(一)读源码,我们可以从第一行读起 Spring执行流程图如下: 如果图片 ...

  10. 浅析java中ClassLoader如何加载Class

    我的博客地址:https://blog.csdn.net/qq_41907991 ClassLoader是一个经常出现又让很多人望而却步的词.本文试图以最浅显易懂的方式来讲解ClassLoader,希 ...