关于NodeJs的总结和补充
- 1.谈谈对NodeJs的理解
- 2.NodeJs的使用场景
- 3.为什么要用NodeJs
- 4.NodeJs有哪些全局对象?
- 5.关于NodeJS中的process
- 6.console有哪些常用方法?
- 7.Node.js有哪些定时功能?
- 8.谈谈Node.js的fs模块
- 9.谈谈Node.js中的Buffer
- 10.谈谈Node.js的Stream
- 11.关于EventEmitter
- 12.Nodejs的子进程
- 14.如何让一个JavaScript文件变得像Linux命令一样可执行?
- 15.谈谈栈和堆的区别
- 16.node的三大模块
- 17.说说 Node 文件查找的优先级以及 Require 方法的文件查找策略?
- 18.自定义本地包和全局包
- 19.关于nodejs的中间件
- 20.Nodejs通过哪些方法可以进行异步流程的控制
- 21.知道node中的route, middleware, cluster, nodemon, pm2, server-side rendering么?
1.谈谈对NodeJs的理解
Node. js是一个基于Chrome v8引擎的服务器端JavaScript运行环境。
2.NodeJs的使用场景
- 快速编写接口和中间件
- 基于Express框架,可以快速构建Web应用
- 基于Electron框架,可以快速构建跨平台的桌面应用
- 基于restify框架,可以快速构建API接口项目
- 读写和操作数据库。创建使用的命令行工具辅助前端开发
- etc…
3.为什么要用NodeJs
原因如下。
- 简单, Node. js用 JavaScript、JSON进行编码,简单好学。
- 功能强大,非阻塞式I/O,在较慢的网络环境中,可以分块传输数据,事件驱动,擅长高并发访问
- 轻量级, Node. js本身既是代码又是服务器,前后端使用同一语言。
- 可扩展,可以轻松应对多实例、多服务器架构,同时有海量的第三方应用组件。
4.NodeJs有哪些全局对象?
- global:
这是Node.js中最根本的全局对象,类似于浏览器中的window对象。所有的全局变量(除了global本身)都是global对象的属性。 - process:
这是一个提供有关当前Node.js进程的信息并与之交互的对象。它提供了诸如环境变量、命令行参数、进程版本、操作系统等信息,并且可以用来退出进程。例如,process.env
用于访问环境变量,process.argv
用于获取命令行参数。 - console:
这是一个用于打印输出到stdout和stderr的对象。它提供了诸如console.log()
,console.error()
,console.warn()
等方法。 - Buffer:
这是一个全局可用的类型,用于处理二进制数据。在Node.js中,由于JavaScript原生不支持二进制数据,因此Buffer类被引入来处理这种情况。例如,读取文件时通常会得到Buffer对象,然后可以将其转换为字符串或其他格式。 - setImmediate, setTimeout, setInterval, clearTimeout, clearInterval:
这些是Node.js中的全局函数,用于处理和控制异步操作。setImmediate
用于将回调函数排入队列,在当前事件循环结束时执行。setTimeout
和setInterval
用于在指定的毫秒数后执行回调函数,或者每隔指定的毫秒数执行回调函数。clearTimeout
和clearInterval
用于取消由setTimeout
和setInterval
设置的定时器。 - __filename:
这是一个包含当前模块文件路径的全局变量。 - __dirname:
这是一个包含当前模块目录路径的全局变量。 - module 和 exports/require:
虽然它们通常被视为模块级别的对象,但在每个模块内部,它们实际上是全局可访问的。module
表示当前模块,exports
是模块导出的对象,require
函数用于引入其他模块。
5.关于NodeJS中的process
5.1 process是什么
process翻译过来是进程的意思,学习过计算机系统的人都知道,进程是计算机系统进行资源分配和调度的基本单位。每个进程享有独立的空间地址和数据栈。也就是说不同的进程间不能直接访问数据,需要经过通信后,才能互相访问数据。process对象是一个全局变量,提供了node进程的信息并对其进行控制。
5.2 process常用的属性和方法
5.2.1 process.cwd()
- 返回当前Node进程执行的目录
- 如果一个Node模块A通过NPM发布,项目B中使用了模块A,在A中需要操作B项目下的文件时,就可以用
process.cwd
来获取B的路径。
console.log(process.cwd())//E:\project\store2
5.2.2 process.env
- 返回一个对象,存储当前环境有关的所有信息
- 我们一般会在process.env上面挂代码环境变量
- 比如process.env.NODE_ENV
- 在vue-cli的源码中也有
process.env.VUE_CLI_DEBUG
标明debug模式
console.log(process.env)
5.2.3 process.argv
- 在终端通过Node执行命令的时候,通过process.agrv可以获取传入的命令行参数,返回值是一个数组
- index(0);路径
- index(1);被执行的js文件路径
- index(2-n);真实传入的命令参数
- 假设我们有一个node.js,然后在终端运行,并在后面跟上参数2025,输
node node.js 2025
,回车:
console.log(process.argv)
// [
// 'D:\\software\\nodejs\\node.exe',
// 'E:\\project\\store2\\node.js',
// '2025'
// ]
5.2.4 process.nextTick()
因为node是基于事件循环的,在一个时间点只能处理一件事情,process.nextTick()
的作用是定义出一个动作,并让这个动作在下一个事件轮询的时间点上执行。
function say(){
console.log('nextTick-say')
}
process.nextTick(say)
console.log('console.log-say')
// console.log-say
// nextTick-say
say被放在下一次事件循环处理了,所以后打印。当然我们也可以使用setTimeout来实现:
function say(){
console.log('nextTick-say')
}
setTimeout(say,0)
console.log('console.log-say')
// console.log-say
// nextTick-say
区别在于,process.nextTick()
在一次事件循环结束call stack清空后再调用callback;而setTimeout并不知道事件循环什么时候结束,所以调用callback的时机不确定。
5.2.5 其它
process.stdin
、 process.stdout
、process.stderr
、process.on
、 process.arch
、process.platform
、 process.exit
…
process.stdin 和 process.stdout 是两个至关重要的模块,它们直接与操作系统的标准输入和标准输出流进行交互。它们使得 Node.js 应用可以与用户或其他进程进行数据通信。
process.stdout
属性返回一个对象,表示标准输出。该对象的write方法等同于console.log,可用在标准输出向用户显示内容。
process.stdout.write('Hello World')
输出结果为:
process.stdin
返回一个对象,表示标准输入。
process.stdout.write('请输入数据:')
process.stdin.on('data',(data)=>{
process.stdout.write("输入的数据是:"+data.toString().trim())
process.exit(0) //结束进程
})
打印结果为:
5.2.6 总结
console.log('进程号',process.pid)
console.log('操作系统',process.platform)
console.log('Node版本',process.version)
console.log('所有命令行参数:',process.argv)
6.console有哪些常用方法?
- console.log/console.info/console.error/console.warning
- console.time/console.timeEnd
- console.trace
- console .table。
7.Node.js有哪些定时功能?
- setTimeout/clearTimeout,
- setInterval/clearInterval
- setImmediate/clearImmediate
- process.nextTick
8.谈谈Node.js的fs模块
fs 模块是Node.js官方提供的、用来操作文件的模块。fs(filesystem),该模块提供本地文件的读写能力,基本上是POSIX文件操作命令的简单包装。可以说,所有与文件的操作都是通过fs核心模块实现。
这个模块对所有文件系统操作提供异步(不具有sync 后缀)和同步(具有 sync 后缀)两种操作方式,而供开发者选择。
fs.watch和fs.watchFile有什么区别?
二者主要用来监听文件变动,fs.watch利用操作系统原生机制来监听,可能不适用网络文件系统;fs. watchFile则定期检查文件状态变更,适用于网络文件系统,但是与fs.watch相比有些慢,因为它不采用实时机制。
9.谈谈Node.js中的Buffer
在Node应用中,需要处理网络协议、操作数据库、处理图片、接收上传文件等,在网络流和文件的操作中,要处理大量二进制数据,而Buffer(缓冲区)就是在内存中开辟一片区域(初次初始化为8KB),用来存放二进制数据。
简单来讲,Nodejs不能控制数据传输的速度和到达时间,只能决定何时发送数据,如果还没到发送时间,则将数据放在Buffer中,即在RAM中,直至将它们发送完毕。
Buffer是用来存储二进制数据,其的形式可以理解成一个数组,数组中的每一项,都可以保存8位二进制:00000000,也就是一个字节。
关于buffer详情可见我写的博客https://blog.csdn.net/fageaaa/article/details/146610452
10.谈谈Node.js的Stream
流(Stream),是一个数据传输手段,是端到端信息交换的一种方式,而且是有顺序的,是逐块读取数据、处理内容,用于顺序读取输入或写入输出。
它的独特之处在于,它不像传统的程序那样一次将一个文件读入内存,而是逐块读取数据、处理其内容,而不是将其全部保存在内存中。
流可以分成三部分:
- source 源数据
- dest 目的地
- pipe 运输管道
在source和dest之间有一个连接的管道pipe,它的基本语法是source.pipe(dest)
,source和dest就是通过pipe连接,让数据从source流向了dest。
在NodeJS,几乎所有的地方都使用到了流的概念,分成四个种类:
- 可写流:可写入数据的流。例如 fs.createWriteStream() 可以使用流将数据写入文件
- 可读流: 可读取数据的流。例如fs.createReadStream() 可以从文件读取内容
- 双工流: 既可读又可写的流。例如 net.Socket
- 转换流: 可以在数据写入和读取时修改或转换数据的流。例如,在文件压缩操作中,可以向文件写入压缩数据,并从文件中读取解压数据。
11.关于EventEmitter
11.1 EventEmitter简介
EventEmitter是 Node.js中一个实现观察者模式的类,主要功能是订阅和发布消息,用于解决多模块交互而产生的模块之间的耦合问题。
11.2 如何实现一个EventEmitter?
可通过3步实现 EventEmitter定义一个子类,通过寄生组合式继承,继承 EventEmitter。
var Util= require('util' );
var EventEmitter= require ('events');
function IcktEmitter () {
EventEmitter.apply(this, arguments)
}
Util.inherits(IcktEmitter, EventEmitter);
var ie = new IcktEmitter ( ) ;
ie.on('icketang',function(data){
console.log('接收到消息',data )
})
ie.emit('icketang','来自有课网的消息');
12.Nodejs的子进程
12.1 exec、 execFile、 spawn和fork都是做什么用的?
方法 | 区别 | 适用场景 |
---|---|---|
exec | 执行 shell 命令,创建 shell进程 | 执行简单命令,获取输出和错误信息 |
execFile | 执行可执行文件 | 执行编译好的二进制文件,获取输出和错误信息 |
fork | 衍生 Node.js 子进程,执行 JS 文件 | 创建独立的子进程并与父进程通过消息通信 |
spawn | 执行命令,不创建 shell 进程 | 执行复杂命令,流式处理输入输出 |
12.2 如何实现一个简单的命令行交互程序?
var cp = require (' child process );
//执行指令
var child= cp .spawn('echo', ['hello, ''] );
// child.stdout是输入流, process. stdout是输出流
//子进程的输出流作为当前程序的输入流,然后重定向到当前程序的控制器输出
child. stdout. pipe(process. stdout)
12.3 两个Node.js程序之间如何交互?
通过fork实现父子程序之间的交互。子程序用 process.on、 process. send访问父程序,父程序用 child.on、 child.send访问子程序。
//parent.js
let cp =require('child_process');
let child=cp.fork('./child.js');
child.on('message',function(msg){
console.log('子程序发送的数据:',msg)
})
child.send ( '来自父程序发送的数据')
//child.js
process.on('message',function(msg){
console.log ('父程序发送的数据:', msg)
process.send ( '来自子程序发送的数据')
})
14.如何让一个JavaScript文件变得像Linux命令一样可执行?
创建 JavaScript 文件:例如,创建一个名为 test.js 的文件,内容如下:
console.log("Hello, World!");
在文件的顶部添加 #!/usr/bin/env node
,这告诉系统使用 Node.js 来执行这个文件。
#!/usr/bin/env node
console.log("Hello, World!");
使文件可执行:在终端中,运行以下命令来使文件具有执行权限:
运行文件:现在你可以像运行普通命令一样运行你的 JavaScript 文件了:
15.谈谈栈和堆的区别
区别如下:
(1)栈( stack)区由编译器自动分配和释放,存放函数的参数值、局部变量的值等。
堆(heap)区一般由程序员分配和释放,若程序员不释放,程序结束时可能由OS回收。
(2)堆(数据结构)可以被看成一棵树,如堆排序。栈(数据结构)是一种先进后出的数据结构。
16.node的三大模块
Node.js 应用由模块组成,采用 CommonJS 模块规范。Node.js中的模块分为三种:
- 内置模块
- 第三方模块
- 自定义模块
其中内置模块如下:
- FS:文件系统模块
- path:路径模块
- OS:操作系统相关
- net:网络相关
- http
- url
- events 用于处理事件。该模块提供了事件发射器(EventEmitter)的功能,可以用于创建和管理事件。例如,可以使用EventEmitter来订阅和触发事件
- crypto 用于加密和解密数据。该模块提供了加密算法和哈希算法等功能,常用于数据安全处理
- …
17.说说 Node 文件查找的优先级以及 Require 方法的文件查找策略?
通过require函数导入其他模块(自定义模块、系统模块、第三方库模块)中的内容,require参数较为简单,但是内部的加载却是十分复杂的,其加载优先级也各自不同。
(1) 缓存的模块优先级最高
(2) 如果是内置模块,则直接返回,优先级仅次缓存的模块
(3) 如果是绝对路径 / 开头,则从根目录找
(4) 如果是相对路径 ./开头,则从当前require文件相对位置找
(5) 如果文件没有携带后缀,先从js、json、node按顺序查找
(6) 如果是目录,则根据 package.json的main属性值决定目录下入口文件,默认情况为 index.js
(7) 如果文件为第三方模块
require('第三方包名')
优先在加载该包的模块的同级目录node_modules
中查找第三方包。- 找到该第三方包中的
package.json
文件,并且找到里面的main
属性对应的入口模块,该入口模块即为加载的第三方模块。 - 如果在要加载的第三方包中没有找到
package.json
文件或者是package.json
文件中没有main
属性,则默认加载第三方包中的index.js
文件。 - 如果在加载第三方模块的文件的同级目录没有找到
node_modules
文件夹,或者以上所有情况都没有找到,则会向上一级父级目录下查找node_modules
文件夹,查找规则如上一致。 - 如果一直找到该模块的磁盘根路径都没有找到,则会报错:
can not find module xxx
。
18.自定义本地包和全局包
18.1 什么是包
包就是一个文件夹,用来管理模块和模块之间的各种关系。
18.2 包的规范(了解)
- package.json必须在包的顶层目录下。
- 二进制文件应该在bin目录下。
- JavaScript代码应该在lib目录下。
- 文档应该在doc目录下。
- 单元测试应该在test目录下。
18.3 package.json字段分析(了解)
- name:包的名称,必须是唯一的,由小写英文字母、数字和下划线组成,不能包含空格
- description:包的简要说明。
- version:符合语义化版本识别规范的版本字符串。
- 主版本号:当你做了不兼容的API修改。
- 子版本号:当你做了向下兼容的功能性新增。
- 修订号:当你做了向下兼容的问题修正。
- keywords:关键字数组,通常用于搜索。
- maintainers:维护者数组,每个元素要包含name、email(可选)、web(可选)字段
- contributors:贡献者数组,格式与maintainers相同。包的作者应该是贡献者数组的第一个元素。
- bugs:提交bug的地址,可以是网站或者电子邮件地址。
- licenses:许可证数组,每个元素要包含type(许可证名称)和URL(连接到许可证文本的地址)字段。
- repositories:仓库托管地址数组,每个元素要包含type(仓库类型,如git)、url(仓库地址)和path(相对于仓库的路径,可选)字段。
- dependencies:生产环境包的依赖,一个关键数组,由包的名称和版本号组成。
- devDependencies:开发环境包的依赖,一个关联数组,由包的名称和版本号组成。
- main:指定包入口文件,如果没有配置main,默认会将index.js作为入口,如果包中没有index.js,那么就必须配置main。
- scripts:(1)保存一些常用的指令,可以通过npm run key方式运行。(2)应用场景:每次执行某个js文件都需要传递参数,并且每次传递的参数都是一样的,那么就可以通过将指令保存到script中来简化输入指令的操作。(通过指令执行某个文件的时候可以传递一个参数,并且该文件可以通过process.argv拿到这个参数。scripts可以简化执行命令)
18.4 自定义包实现步骤
- 创建一个包文件夹。
- 初始化一个package.json文件。
- 初始化一个包入口js文件。
注意点:如果没有配置main,默认会将index.js作为入口,如果包中没有index.js,那么就必须配置main。 - 根据包信息配置package.json文件。
注意点:通过scripts可以帮助我们记住指令,然后通过npm run xxx方式,就可以执行该指令。如果指令的名称叫做start或者test,那么执行的时候可以不加run。
全局包:一般全局包都是些工具包比如nrm、yarn、cnpm等,工具包的特点需要自定义指令。
- 给package.json添加bin属性,告诉系统执行全局命令式时需要执行哪一个JS文件。
- 在全局命令执行的JS文件中添加#! /usr/bin/envnode。 (node环境执行)
- 通过npm link 将本地包放到全局方便我们调试。
19.关于nodejs的中间件
在现代 web 开发中,尤其是在使用 Node.js 和 Express 框架时,中间件(Middleware)这一概念频频出现在开发者的视野中。作为理解和使用这些技术的基础,掌握中间件的概念和应用方法对于开发高效、可维护的应用至关重要。
19.1 什么是中间件
node中间件主要是指封装http请求细节处理的方法,其本质上就是在进入具体的业务处理之前,先让特定过滤器处理;对于Web应用而言,引入Node中间件可以简化和封装一些基础逻辑处理细节。
19.2 中间件的格式
注意:中间件函数的形参列表中,必须包含 next 参数。而路由处理函数中只包含 req 和 res。
19.3 封装node中间件示例
19.3.1 创建中间件函数
首先,你需要创建一个函数,该函数接收三个参数:req、res和next。next是一个函数,用于调用下一个中间件。
function myMiddleware(req, res, next) {
// 在这里添加你的逻辑
console.log('Middleware is running');
// 调用下一个中间件
next();
}
19.3.2 使用Express应用注册中间件
在你的Express应用中,你可以使用.use()方法来注册中间件。
const express = require('express');
const app = express();
// 注册全局中间件
app.use(myMiddleware);
// 其他路由或中间件
app.get('/', (req, res) => {
res.send('Hello World!');
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
19.3.3 封装为一个模块
为了更好地组织代码,你可以将中间件封装成一个模块。
//myMiddleware.js:
function myMiddleware(req, res, next) {
console.log('Middleware is running');
next();
}
module.exports = myMiddleware;
然后在你的主应用文件中引入并使用它:
const express = require('express');
const app = express();
const myMiddleware = require('./myMiddleware'); // 引入中间件模块
app.use(myMiddleware); // 使用中间件
app.get('/', (req, res) => {
res.send('Hello World!');
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
20.Nodejs通过哪些方法可以进行异步流程的控制
20.1 callback回调函数
fs.readFile('/path/to/file', 'utf8', (err, data) => {
if (err) throw err;
console.log(data);
});
20.2 Promises
const promise = new Promise((resolve, reject) => {
// 模拟异步操作
setTimeout(() => {
resolve('Success!');
// 或在出错时调用 reject('Error!')
}, 1000);
});
promise.then(result => {
console.log(result); // 输出 "Success!"
}).catch(error => {
console.error(error);
});
20.3 async/await
async function fetchAndLog() {
const result = await someAsyncFunction(); // 假设这是一个返回 Promise 的异步函数
console.log(result);
}
fetchAndLog().catch(error => {
console.error('Error:', error);
});
20.4 流(Streams)
const readableStream = fs.createReadStream('file.txt');
readableStream.on('data', chunk => {
console.log(`Received ${
chunk.length} bytes of data.`);
});
readableStream.on('end', () => {
console.log('No more data.');
});
20.5 Child Processes(子进程)
const {
exec } = require('child_process');
exec('ls -lh', (error, stdout, stderr) => {
if (error) {
console.error(`执行出错: ${
error}`);
return;
}
console.log(`stdout: ${
stdout}`);
console.error(`stderr: ${
stderr}`);
});
21.知道node中的route, middleware, cluster, nodemon, pm2, server-side rendering么?
- route 路由
- middleware 中间件
- cluster 集群
- nodemon 用于监控文件的变化并自动重启服务器的工具
- pm2 进程管理工具
- server-side rendering 服务端渲染
nodemon是什么?(了解)
Nodemon 是 Node.js 生态系统中一款非常实用的开发工具,用于监控文件的变化并自动重启服务器,从而提升开发效率。特别是在后端开发过程中,频繁的代码修改和重启服务器操作极为繁琐,而 Nodemon 通过自动化这些流程,让开发者能够专注于代码本身。本文将详细介绍 Nodemon 的基本使用方法、配置选项及其在实际开发中的应用场景。
pm2是什么?(了解)
PM2是一个进程管理工具,专门用于管理和监控Node.js应用程序。 PM2不仅可以启动和管理Node.js应用,还可以进行性能监控、自动重启、负载均衡、进程守护和零秒重载等功能。它支持Linux、MacOS和Windows等多个操作系统,是Node.js开发者管理和监控应用程序的首选工具之一。