node 核心内置类库 事件、流、文件、网络

发布于 2023-05-20 11:02:18 字数 7972 浏览 38 评论 0

node 概览

为什么要用 node?

总结起来 node 有以下几个特点:简单强大,轻量可扩展。简单体现在 node 使用的是 javascript,json 来进行编码,人人都会;强大体现在非阻塞 IO,可以适应分块传输数据,较慢的网络环境,尤其擅长高并发访问;轻量体现在 node 本身既是代码,又是服务器,前后端使用统一语言,可扩展体现在可以轻松应对多实例,多服务器架构,同时有海量的第三方应用组件。

node 的构架是什么样子的?

主要分为三层,应用 app >> V8 及 node 内置架构 >> 操作系统,V8 是 node 运行的环境,可以理解为 node 虚拟机。node 内置架构又可分为三层:核心模块(javascript 实现) >> c++ 绑定 >> libuv + CAes + http。

node 有哪些核心模块?

EventEmitter、Stream、FS、Net 和全局对象

node 全局对象

node 有哪些全局对象?

process、console、Buffer 和 exports

process 有哪些常用方法?

process.stdin, process.stdout, process.stderr, process.on, process.env, process.argv, process.arch, process.platform, process.exit

console 有哪些常用方法?

console.log/console.info、console.error/console.warning、console.time/console.timeEnd、console.trace、console.table

node 有哪些定时功能?

setTimeout/clearTimeout、setInterval/clearInterval、setImmediate/clearImmediate、process.nextTick

node 中的事件循环是什么样子的?

event loop 其实就是一个事件队列,先加入先执行,执行完一次队列,再次循环遍历看有没有新事件加入队列,但是请务必注意,这一个事件队列的循环,一次只执行一个事件,然后下一次循环再执行一个事件。这是由于 javascript 的单线程机制导致的,如果一次循环多个事件,就可能会阻塞其它代码的执行。

异步执行的叫 IO events,setImmediate 是在当前队列立即执行,setTimout/setInterval 是把执行定时到到后面的队列,process.nextTick 是在当前执行完,下次遍历前执行。所以总体顺序是:IO events >> setImmediate >> setTimeout/setInterval(注册事件) >> process.nextTick.

node 中的 Buffer 如何应用?

Buffer 是用来处理二进制数据的,比如图片、mp3、数据库文件等。Buffer 支持各种编码解码,二进制字符串互转。

EventEmitter

什么是 EventEmitter?

EventEmitter是node中一个实现观察者模式的类,主要功能是监听和发射消息,用于处理多模块交互问题。

如何实现一个 EventEmitter?

主要分三步:定义一个子类,调用构造函数,继承 EventEmitter

var util = require('util');
var EventEmitter = require('events').EventEmitter;

function MyEmitter() {
  EventEmitter.call(this);
} // 构造函数

util.inherits(MyEmitter, EventEmitter); // 继承

var em = new MyEmitter();
em.on('hello', function(data) {
  console.log('收到事件hello的数据:', data);
}); // 接收事件,并打印到控制台
em.emit('hello', 'EventEmitter传递消息真方便!');

EventEmitter 有哪些典型应用?

  1. 模块间传递消息
  2. 回调函数内外传递消息
  3. 处理流数据,因为流是在 EventEmitter 基础上实现的
  4. 观察者模式发射触发机制相关应用

怎么捕获 EventEmitter 的错误事件?

监听 error 事件即可,如果有多个 EventEmitter,也可以用 domain 来统一处理错误事件。

var domain = require('domain');
var myDomain = domain.create();
myDomain.on('error', function(err){
  console.log('domain接收到的错误事件:', err);
}); // 接收事件并打印
myDomain.run(function(){
  var emitter1 = new MyEmitter();
  emitter1.emit('error', '错误事件来自emitter1');
  emitter2 = new MyEmitter();
  emitter2.emit('error', '错误事件来自emitter2');
});

EventEmitter 中的 newListenser 事件有什么用处?

newListener 可以用来做事件机制的反射,特殊应用,事件管理等。当任何 on 事件添加到 EventEmitter 时,就会触发 newListener 事件,基于这种模式,我们可以做很多自定义处理。

var emitter3 = new MyEmitter();
emitter3.on('newListener', function(name, listener) {
	console.log("新事件的名字:", name);
	console.log("新事件的代码:", listener);
	setTimeout(function(){ console.log("我是自定义延时处理机制"); }, 1000);
});
emitter3.on('hello', function(){
	console.log('hello node');
});

Stream

什么是 Stream?

stream 是基于事件 EventEmitter 的数据管理模式。由各种不同的抽象接口组成,主要包括可写,可读,可读写,可转换等几种类型。

Stream 有什么好处?

非阻塞式数据处理提升效率,片断处理节省内存,管道处理方便可扩展等。

Stream 有哪些典型应用?

文件,网络,数据转换,音频视频等。

怎么捕获 Stream 的错误事件?

监听 error 事件,方法同 EventEmitter。

    1. 有哪些常用 Stream,分别什么时候使用?

Readable 为可被读流,在作为输入数据源时使用;Writable 为可被写流,在作为输出源时使用;Duplex 为可读写流,它作为输出源接受被写入,同时又作为输入源被后面的流读出。Transform 机制和 Duplex 一样,都是双向流,区别时 Transfrom 只需要实现一个函数 _transfrom(chunk, encoding, callback); 而 Duplex 需要分别实现 _read(size) 函数和 _write(chunk, encoding, callback) 函数。

实现一个 Writable Stream?

三步走:

  1. 构造函数 call Writable
  2. 继承 Writable
  3. 实现 _write(chunk, encoding, callback) 函数
var Writable = require('stream').Writable;
var util = require('util');

function MyWritable(options) {
	Writable.call(this, options);
} // 构造函数
util.inherits(MyWritable, Writable); // 继承自Writable
MyWritable.prototype._write = function(chunk, encoding, callback) {
	console.log("被写入的数据是:", chunk.toString()); // 此处可对写入的数据进行处理
	callback();
};

process.stdin.pipe(new MyWritable()); // stdin作为输入源,MyWritable作为输出源   

文件系统

内置的 fs 模块架构是什么样子的?

fs 模块主要由下面几部分组成:

  • POSIX 文件 Wrapper,对应于操作系统的原生文件操作
  • 文件流 fs.createReadStream 和 fs.createWriteStream
  • 同步文件读写 fs.readFileSync 和 fs.writeFileSync
  • 异步文件读写 fs.readFile 和 fs.writeFile

读写一个文件有多少种方法?

总体来说有四种:

  • POSIX 式低层读写
  • 流式读写
  • 同步文件读写
  • 异步文件读写

怎么读取 json 配置文件?

主要有两种方式,第一种是利用 node 内置的 require('data.json') 机制,直接得到 js 对象,第二种是读入文件入内容,然后用 JSON.parse(content) 转换成 js 对象

二者的区别是 require 机制情况下,如果多个模块都加载了同一个 json 文件,那么其中一个改变了 js 对象,其它跟着改变,这是由 node 模块的缓存机制造成的,只有一个 js 模块对象,第二种方式则可以随意改变加载后的 js 变量,而且各模块互不影响,因为他们都是独立的,是多个 js 对象。

fs.watch 和 fs.watchFile 有什么区别,怎么应用?

二者主要用来监听文件变动,fs.watch 利用操作系统原生机制来监听,可能不适用网络文件系统,fs.watchFile 则是定期检查文件状态变更,适用于网络文件系统,但是相比 fs.watch 有些慢,因为不是实时机制。

网络

node 的网络模块架构是什么样子的?

node 全面支持各种网络服务器和客户端,包括 tcp、http/https、tcp、udp、dns、tls/ssl 等。

node 是怎样支持 https、tls 的?

主要实现以下几个步骤即可:

  1. openssl 生成公钥私钥
  2. 服务器或客户端使用 https 替代 http
  3. 服务器或客户端加载公钥私钥证书

实现一个简单的 http 服务器?

经典又很没毛意义的一个题目,思路是加载 http 模块,创建服务器,监听端口。

var http = require('http'); // 加载http模块

http.createServer(function(req, res) {
  res.writeHead(200, {'Content-Type': 'text/html'}); // 200代表状态成功, 文档类型是给浏览器识别用的
  res.write('<meta charset="UTF-8"><h1>我是标题啊!</h1><font color="red">这么原生,初级的服务器,下辈子能用着吗?!</font>'); // 返回给客户端的html数据
  res.end(); // 结束输出流
}).listen(3000); // 绑定3ooo, 查看效果请访问 http://localhost:3000 

child-process

为什么需要 child-process?

node 是异步非阻塞的,这对高并发非常有效。可是我们还有其它一些常用需求,比如和操作系统 shell 命令交互,调用可执行文件,创建子进程进行阻塞式访问或高CPU 计算等,child-process 就是为满足这些需求而生的。child-process 顾名思义,就是把 node 阻塞的工作交给子进程去做。

exec、execFile、spawn 和 fork 都是做什么用的?

  • exec 可以用操作系统原生的方式执行各种命令,如管道 cat ab.txt | grep hello
  • execFile 是执行一个文件
  • spawn 是流式和操作系统进行交互
  • fork 是两个 node 程序(javascript)之间时行交互

实现一个简单的命令行交互程序?

那就用 spawn

var cp = require('child_process');

var child = cp.spawn('echo', ['你好', "钩子"]); // 执行命令
child.stdout.pipe(process.stdout); // child.stdout是输入流,process.stdout是输出流
// 这句的意思是将子进程的输出作为当前程序的输入流,然后重定向到当前程序的标准输出,即控制台

两个 node 程序之间怎样交互?

用 fork,上面讲过了,原理是子程序用 process.on、process.send,父程序里用 child.on、child.send 进行交互。

1) fork-parent.js
var cp = require('child_process');
var child = cp.fork('./fork-child.js');
child.on('message', function(msg){
  console.log('老爸从儿子接受到数据:', msg);
});
child.send('我是你爸爸,送关怀来了!');

2) fork-child.js
process.on('message', function(msg){
  console.log("儿子从老爸接收到的数据:", msg);
  process.send("我不要关怀,我要银民币!");
});

怎样让一个 js 文件变得像 linux 命令一样可执行?

  • 在 myCommand.js 文件头部加入 #!/usr/bin/env node
  • chmod 命令把 js 文件改为可执行即可
  • 进入文件目录,命令行输入 myComand 就是相当于 node myComand.js 了

child-process 和 process 的 stdin、stdout、stderror 是一样的吗?

概念都是一样的,输入,输出,错误,都是流。区别是在父程序眼里,子程序的 stdout 是输入流,stdin 是输出流。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

JSmiles

生命进入颠沛而奔忙的本质状态,并将以不断告别和相遇的陈旧方式继续下去。

0 文章
0 评论
84960 人气
更多

推荐作者

金兰素衣

文章 0 评论 0

ゃ人海孤独症

文章 0 评论 0

一枫情书

文章 0 评论 0

清晰传感

文章 0 评论 0

mb_XvqQsWhl

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文