Nodejs核心功能模块理解
在开始介绍Nodejs中的核心模块之前,我们先对几个我们必须掌握的,也是使用频率非常高的模块做一个总览(注意,由于已经有其它很好的文章详细介绍模块API的使用,因此本文中并不再赘述,而是更着重梳理对于每一个模块的理解和应用场景,并在贴出详细的参考资料,请谨慎食用)
1.Buffer——Nodejs用来处理二进制流数据或者与之交互
2.Stream——Nodejs用来缓解CPU运算压力,一边读取一边返回数据
3.events——事件触发器,触发命名事件来调用函数
4.http(Https)——作为服务端使用时,创建一个HTTP服务器,监听HTTP客户端请求并返回响应。作为客户端使用时,发起一个HTTP客户端请求,获取服务端响应。
5.net——提供了异步网络API来创建基于流的TCP或者IPC服务器和客户端
6.process——不是内置模块,而是一个全局对象,用来感知和控制NodeJS自身进程的方方面面
7.fs—— fs 模块是文件操作的封装,它提供了文件读取、写入、更名、删除、遍历目录、链接等 POSIX 文件系统操作,有异步和同步两个版本
8.vm——引用官方网站的原文,vm(Virtual Machine),即使用V8虚拟机上下文来运行和编译代码,特别注明,这不是一个安全的机制,不要用其运行不受信任的 代码。
9.cluster——由于js是单线程的,cluster模块就提供了一系列的API,方便用户充分利用计算机多核性能,启动nodejs集群
一、Buffer
Nodejs中的Buffer(缓存)类是一个类似于数组,默认以十六进制来保存资源在计算机当中的二进制形式,与Stream也就是流的概念密切相关,其主要的作用就是提供操作处理二进制流数据的API
js不能控制数据到达的速度或时间,也不能控制流的速度。它只能决定何时发送数据。如果还没有到时间,Node.js将把它们放在buffer中,即RAM中的一个小位置,直到将它们发送出去进行处理为止。
对于Buffer,我们需要思考的问题如下:
(1)字符从输入到存储到计算机的表现形式和最终用Buffer表现的过程?
(2)Buffer类的应用场景?
- I/O操作(读写文件、TCP协议、RPC层)
- zlib.js
- 加解密
(3)Buffer与Cache之间的关系?
缓冲(Buffer)是用于处理二进制流数据,将数据缓冲起来,它是临时性的,对于流式数据,会采用缓冲区将数据临时存储起来,等缓冲到一定的大小之后在存入硬盘中。视频播放器就是一个经典的例子,有时你会看到一个缓冲的图标,这意味着此时这一组缓冲区并未填满,当数据到达填满缓冲区并且被处理之后,此时缓冲图标消失,你可以看到一些图像数据。
缓存(Cache)我们可以看作是一个中间层,它可以是永久性的将热点数据进行缓存,使得访问速度更快,例如我们通过 Memory、Redis
等将数据从硬盘或其它第三方接口中请求过来进行缓存,目的就是将数据存于内存的缓存区中,这样对同一个资源进行访问,速度会更快,也是性能优化一个重要的点。
(4)Buffer有哪些相关的npm包?
(5)Buffer的基本操作是什么?
- 创建、修改Buffer类型
- Buffer类型与字符之间的相互转化
(6)Buffer的内存分配机制?
二、Stream
Stream首先和Buffer类是密不可分的,是基于Buffer的。
之所以用stream ,是因为一次性读取、操作大文件,内存和网络是“吃不消”的,因此要让数据流动起来,一点一点的进行操作,这其实也符合算法中一个很重要的思想 —— 分而治之
(1)来源
- 从控制台输入
- http请求中的request
- 读取文件
(2)常用的模块类
- event-stream
- awesome-nodejs#streams
(3)核心
- 流的创建
- 为什么需要使用流?弊端有哪些?
- 流的应用实例(http请求、文件读写)
- Stream和Buffer之间的关系
- stream的类型有哪些?
三、events事件触发器
[源码解读]一文彻底搞懂Events模块
Node events(事件触发器)(EventEmitter 类)
该模块使用的就是观察者模式,其核心功能在于事件的绑定和触发,使用频率高。
参考一位大佬写的简易观察者模式。
let officeAccounts ={
// 初始化定义一个存储类型对象
subscribes:{
'any':[]
},
// 添加订阅号
subscribe:function(type='any',fn){
if(!this.subscribes[type]){
this.subscribes[type] = [];
}
this.subscribes[type].push(fn);//将订阅方法存在数组中
},
// 退订
unSubscribe:function(type='any',fn){
this.subscribes[type] =
this.subscribes[type].filter((item)=>{
return item!=fn;// 将退订的方法从数组中移除
});
},
// 发布订阅
publish:function(type='any',...args){
this.subscribes[type].forEach(item => {
item(...args);// 根据不同的类型调用相应的方法
});
}
}
链接:https://juejin.im/post/5d69eef7f265da03f12e70a5
来源:掘金
然后是应用
let xiaoming = {
readArticle:function (info) {
console.log('小明收到的',info);
}
};
let xiaogang = {
readArticle:function (info) {
console.log('小刚收到的',info);
}
};
officeAccounts.subscribe('程序员成长指北',xiaoming.readArticle);
officeAccounts.subscribe('程序员成长指北',xiaogang.readArticle);
officeAccounts.subscribe('某公众号',xiaoming.readArticle);
officeAccounts.unSubscribe('某公众号',xiaoming.readArticle);
officeAccounts.publish('程序员成长指北','程序员成长指北的Node文章');
officeAccounts.publish('某公众号','某公众号的文章');
总结归纳一下:
(1)应用场景
所有触发了事件触发器的实例,都会拥有一个eventEmitter.on()函数,用来绑定监听事件
- net.Server 会在每次有新连接时触发事件
- fs.ReadStream 会在打开文件时触发事件
- stream会在数据可读时触发事件
(2)核心
- on
- emit
- addListener
- removeListener
- 同步还是异步,该如何触发?(process.nextTick、setImmediate)
- newListener
- setMaxListeners(n)和defaultMaxListeners之间的区别
感谢阅读,欢迎批评指正,希望大家能够在追求卓越中不断进步,让优秀成为一种习惯~