异步非阻塞 I/O, 适合处理高并发,统一 js 编程提高开发效率,轻量化 单线程,cpu 密集运算表现差
npm
^ === n.x 不更新主版本 ~ 只更新补丁版本 “>=1.2.3 <=1.2.3” 指定版本范围 无 不更新任何版本
npm config set registry https://registry.npmmirror.com
npm config set proxy http://username:password@your-proxy-server:port
npm config set https-proxy https://registry.npmmirror.com
npm install(i) -g --save(-S) -dev(-D) -exact(-E) package@5.3 安装依赖
npm ci 先删除node_modules,再严格按照锁文件安装,无锁文件或者冲突报错,速度更快,用于生产
npm uninstall -g --save -dev package@ 卸载依赖
npm update -g package@ 更新依赖
npm list(ls) -g 查看全局本地安装的依赖
npm cache clean --force(f) 清除缓存
npm config ls -l 查看配置
npm config set prefix "url" 包管理配置修改
npm config delete name 包管理配置重置
npm init 生成新的package.json文件
npm version(v) 版本
npm info name 依赖包详细信息
npm root 查看依赖安装路径
npm help 命令帮助
npx 直接使用node_modules库,无需全局安装也能使用命令行
node 各版本新特性
版本 | 关键特性 |
---|---|
12 | 正式支持 import/export |
14 | Async Local Storage API, 支持?. |
16 | 支持 Array.prototype.at()等 ES2020 语法, 明确核心模块引用(如 require(‘node:fs’)) |
18 | 全局 fetch API, node –watch |
20 | 原生 .env 支持 node –env-file .env-test, import.meta.resolve |
22 | require() 支持 ESM 模块, node –test, node –run 脚本模式, new WebSocket() API |
24 | 稳定的权限模型:限制文件/子进程访问(–allow-fs-read) |
node 模块
process.env 环境变量 process.argv 脚本携带参数,前两项 node 执行路径, 当前执行路径, arg..
http 模块
//模块引入
const http = require('http');
const fs = require('fs');
//定义端口号,地址
const hostname = '127.0.0.1';
const port = 8000;
//创建web服务器 ,回调函数req代表客户端请求 res服务端响应 http.createClient创建客户端
//server.on('request',function(req,res){})
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
if(req.url !== '/favicon.ico'){
let out = fs.createWriteStream('./log.txt') // 创建写入流
out.write(`请求方法:${req.method} \n`)
out.write(`请求url:${req.url} \n`)
out.write(`请求头对象:${JSON.stringify(req.headers, null, 4)} \n`)
out.write(`请求http版本:${req.httpVersion} \n`)
}
res.end('Hello World');
});
//启动服务器,监听端口
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
//设置服务器超时
server.timeout=1000
//关闭服务器
server.close([callback])
fs 模块
所有操作分为同步和异步方法
// 最原始繁琐写法
const fs = require('fs')
//同步
let fd = fs.openSync('test.txt','w')
fs.writeSync(fd,'test:hello world')
fs.closeSync(fd)
//异步
fs.open('test.txt','w',function(err, fd){
if(err){
console.log(err)
}else{
console.log(fd)
fs.write(fd,'test:hello world',function(err){
if(!err) console.log('文件已关闭')
fs.close(fd,function(err){
if(!err){
console.log('文件已关闭')
}
})
})
}
})
流式数据不会一次将数据读入内存,直接文件读写一次性读入内存大文件性能问题,内存泄漏,卡顿等
Stream流对象可绑定事件:
data - 当有数据可读时触发。
end - 没有更多的数据可读时触发。
error - 在接收和写入过程中发生错误时触发。
finish - 所有数据已被写入到底层系统时触发。
管道流用于流之间数据传输:
a.pipe(b).pipe(c) a数据流写入b数据流再写入c
//简化写入文件
fs.writeFile('test.txt','写入的内容',function(err){
if(!err) console.log('写入成功')
})
//流式文件写入
let writeFile = fs.createWriteStream('toPath.txt') // 创建可写流
writeFile.on[once]('data',function(){
console.log('流打开了')
})
writeFile.write('写入文件', 'UTF8')
writeFile.close()
//简化读取文件
fs.readFile('test.txt',function(err, data){
if(!err){
console.log('写入成功:', data)
fs.writeFile('test1.txt',data,function(err){
if(!err) console.log('写入成功')
})
}
})
//流式文件读取
let readFile = fs.createReadStream('toPath.txt') // 创建只读流
readFile.on[once]('data',function(data){
console.log('流打开了')
console.log(data)
})
//可读流数据存入可写流
readFile.pipe(writeFile)
//写入压缩文件
fs.createReadStream('input.txt')
.pipe(zlib.createGzip())
.pipe(fs.createWriteStream('input.txt.gz'));
//解压文件
fs.createReadStream('input.txt.gz')
.pipe(zlib.createGunzip())
.pipe(fs.createWriteStream('input.txt'));
//其他操作
fs.watch(path, callback) 文件内容变化回调,稳定快
fs.watchFile(path, callback) 文件内容变化回调,跨平台
fs.unlink(path, callback) 删除文件
fs.mkdir(path, callback) 创建目录
fs.rmdir(path, callback) 删除目录
fs.readdir(path, callback) 读取目录
fs.exists() 验证路径是否存在
path 模块
__filename 代表执行文件的绝对路径
__dirname 当前执行文件所在的目录
path.normalize(p) 规范化路径,注意'..' 和 '.'。
path.join([path1][, path2][, ...]) 用于连接路径。该方法的主要用途在于,会正确使用当前系统的路径分隔符,Unix系统是"/",Windows系统是"\"。
path.resolve([from ...], to) 将 to 参数解析为绝对路径。
path.isAbsolute(path) 判断参数 path 是否是绝对路径。
path.relative(from, to) 用于将相对路径转为绝对路径。
path.dirname(p) 返回路径中代表文件夹的部分,同 Unix 的dirname 命令类似。
path.basename(p[, ext]) 返回路径中的最后一部分。同 Unix 命令 bashname 类似。
path.extname(p) 返回路径中文件的后缀名,即路径中最后一个'.'之后的部分。如果一个路径中并不包含'.'或该路径只包含一个'.' 且这个'.'为路径的第一个字符,则此命令返回空字符串。
path.parse(pathString) 返回路径字符串的对象。
path.format(pathObject) 从对象中返回路径字符串,和 path.parse 相反
var path = require("path");
// 格式化路径
console.log('normalization : ' + path.normalize('/test/test1//2slashes/1slash/tab/..'));
// 连接路径
console.log('joint path : ' + path.join('/test', 'test1', '2slashes/1slash', 'tab', '..'));
// 转换为绝对路径
path.resolve('home', 'foo', 'build','aaaa','aadada','../../..', 'asset') //return '/home/foo/asset'
// 路径中文件的后缀名(文件类型)
console.log('ext name : ' + path.extname('main.js'));
其他模块
os模块
os.tmpdir() 返回操作系统的默认临时文件夹。
os.endianness() 返回 CPU 的字节序,可能的是 "BE" 或 "LE"。
os.hostname() 返回操作系统的主机名。
os.type() 返回操作系统名
os.platform() 返回操作系统名
os.arch() 返回操作系统 CPU 架构,可能的值有 "x64"、"arm" 和 "ia32"。
os.release() 返回操作系统的发行版本。
os.loadavg() 返回一个包含 1、5、15 分钟平均负载的数组。
os.totalmem() 返回系统内存总量,单位为字节
os.freemem() 返回操作系统空闲内存量,单位是字节。
os.cpus() 返回一个对象数组,包含所安装的每个 CPU/内核的信息:型号、速度(单位 MHz)、时间(一个包含 user、nice、sys、idle 和 irq 所使用 CPU/内核毫秒数的对象)。
os.networkInterfaces() 获得网络接口列表。
events模块
// 引入 events 模块
var events = require('events');
// 创建 eventEmitter 对象
var eventEmitter = new events.EventEmitter();
eventEmitter.on('some_event', function() {
console.log('some_event 事件触发');
});
eventEmitter.emit('some_event', param1, param2, param3)
cluster模块
const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
console.log(`主进程 ${process.pid} 正在运行`);
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`工作进程 ${worker.process.pid} 已退出`);
});
} else {
// 工作进程可以共享任何 TCP 连接。
// 在本例子中,共享的是 HTTP 服务器。
http.createServer((req, res) => {
res.writeHead(200);
res.end('Hello World');
}).listen(8000);
console.log(`工作进程 ${process.pid} 已启动`);
}
net模块
提供了一些用于底层的网络通信的小工具,包含了创建服务器/客户端的方法,http模块依赖net模块,且用于创建tcp服务器,socket
dns模块
用于解析域名
buffer(缓存区)
弥补js数组,存储二进制数据,16进制表示,一个buffer占用内存一个byte
存储数据超出8位,取最后8位数据
let buf = new Buffer(1024)
buf.write('test string') 写入buffer,返回写入长度
buf.toString('ascii', 0, 5)
buf.toJSON()
buf.concat([buf1, buf2, buf3])
buf.slice()
buf.length
node 踩坑
模块引入缓存
在同一个文件里面,多次引用同一个模块的话,实际上除了第一次引用之外,其它引用都是缓存
// 清空引入模块缓存
var a = require("./module")
console.log(a.name)
a.name="苏南大叔"
console.log(a.name)
// require.cache中保存的是绝对路径,需要先将相对路径转为绝对路径
delete require.cache[require.resolve("./module")]
var a2 = require("./module2")
console.log(a2.name)
express
npm i express
npm i express-session
npm i jsonwebtoken express-jwt
express 接口编写
//router.js
const express = require('express')
cosnt router = express.Router()
router.get('/get',(req,res)=>{
const query = req.query
res.send({
staus:0,
msg:'get成功',
data:query
})
})
/**
post请求
router.post('/post',(req,res)=>{
//获得请求体中包含的url-encoded格式数据
const body = req.body
res.send({
staus:0,
msg:'post成功',
data:body
})
})
*/
module.exports = router
//interface.js
const express = require('express')
const app = express()
/**
post请求需要配置中间件
app.use(express.urlencoded({extended:false}))
*/
/**
解决接口跨域问题cors中间件
cors包含http响应头:
access-control-allow-origin 标识允许哪个域的请求
access-control-allow-headers 默认仅支持客户端发送9个限定请求头
access-control-allow-methods 默认支持发get,post,head(简单请求)
const cors = require('cors')
app.use(cors())
*/
/**
//session中间件
const session = require('express-session')
app.use(session({
secret:'password',
resave:false,
saveUninitialized:true
}))
*/
/**
jwt中间件
const jwt = require('jsonwebtoken')
const expressJWT = require('express-jwt')
const secretKey = 'myPassword'
//解析客户端token,unless不需要访问权限,自动挂载属性req.user
app.use(expressJWT({secret:secretKey}).unless({path:[/^\/api\//]}))
//生成token,发送给客户端
app.post('api/post',function(req,res){
const token = jwt.sign({username:'aa'},secretKey,{expiresIn:'60s'})
res.send({
status:200,
message:'成功',
token:token
})
})
*/
/**
//错误处理中间件
app.use((err,req,res,next)=>{
if(err.name==='UnauthorizedError'){
console.log('失败')
return res.send({
status:401,
message:'token无效',
})
}
return res.send({
status:500,
message:'其他错误',
})
})
*/
const router = require(./router.js)
app.use('/api',router)
app.listen(80,function(){
console.log('test')
})
//请求
http:localhost/api/get?test='testName&password=123'
http:localhost/api/post'
pm2
常用命令
pm2 start bootstrap.js -i 1 -n $APP -o /dev/null -e /dev/nul
pm2 start app.js
$ pm2 start -n demo npm -- run dev
$ pm2 start -n demo ./bin/www
# 指定应用程序名称
--name <app_name>
# 当文件改变时,观察并重新启动应用程序
--watch
# 设置应用程序重新加载的内存阈值
--max-memory-restart <200MB>
# 指定日志文件
--log <log_path>
# 向脚本传递额外的参数
-- arg1 arg2 arg3
# 自动重启延迟
--restart-delay <delay in ms>
# 使用时间作为日志前缀
--time
# 不自动重启应用程序
--no-autorestart
# 指定cron强制重启
--cron <cron_pattern>
# 附加到应用程序日志
--no-daemon