一、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. 对包含HttpContext.Current.Cache的代码进行单元测试

    假设我们如下代码调用了HttpContext.Current.Cache 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class CacheManager { ...

  2. 原生JS设计轮播图

    一.效果预览: 由于只能上传2M以下的图片,这里只截取了自动切换的效果: 二.编写语言 HTML.CSS.原生JS 三.编写思路 (一)HTML部分 1..slide意为滑槽,里面存放所有图片: 2. ...

  3. 让pomelo可以获取到反向代理websockets的真实用户IP

    /node_modules/pomelo/lib/connectors/hybridsocket.js 找到 var Socket = function(id, socket) { 给remoteAd ...

  4. Egg Dropping Puzzle

    The Two Egg Problem 曾经是Google的一道经典题. 题意:有一个百层高楼,鸡蛋在\(L\)层及以下扔都不碎,在\(L\)层以上都会碎.现在某人有\(k\)个鸡蛋,问在最坏情况下, ...

  5. 网络流--最大流--POJ 2139(超级源汇+拆点建图+二分+Floyd)

    Description FJ's cows really hate getting wet so much that the mere thought of getting caught in the ...

  6. Mysql数据库分页查询

    为什么使用分页查询: 数据量比较大时,如果全部查询,展示刚给用户,数据量太大,用户难以接受.并且数据量大,查询慢.如果此时将大量的数据读取到java内存中,可能会存储崩溃. 分页查询的方式: 1.全部 ...

  7. 12_JavaScript基础入门(2)

    运算符 运算符(Operators,也翻译为操作符),是发起运算的最简单形式. 运算符的分类见仁见智,我们的课程对运算符进行如下分类: 数学运算符(Arithmetic operators)      ...

  8. 【Hadoop离线基础总结】oozie调度MapReduce任务

    目录 1.准备MR执行的数据 2.执行官方测试案例 3.准备我们调度的资源 4.修改配置文件 5.上传调度任务到hdfs对应目录 6.执行调度任务 1.准备MR执行的数据 MR的程序可以是自己写的,也 ...

  9. 关于网上quartus ii 生成fft核出现问题解决

    ------------恢复内容开始------------ 关于网上quartus ii 生成fft核出现问题解决 1:必须把软件破解啦 2:必须把IP核破解啦 破解步骤网上也有可以直接看,一定要全 ...

  10. vs每次生成都全部编译的问题

    最近vs每次生成都会编译整个工程,经查找为.qrc中的资源路径不存在导致,删除路径后问题解决. 原文来自微信公众号"程序员成长日志",已经工作的程序员朋友可以关注下,分享日常工作中 ...