概述
- 什么是node.js
Node js 是javascript运行时的环境而非编程语言
- Node.js中的JavaScript运行环境
NodeJs中分为两部分,一部分是V8引擎为了解析和执行JS代码。另一部分是内置API,内置API提供了一些能力,让我们JS能调用这些API完成一些后端执行的事情。
Node js单线程,适合IO密集性应用
Node.js中无法调用DOM和BOM等浏览器内置API
安装
安装LTS版本(长期维护版)
下载地址:www.nodejs.com.cn/
此时说明已经安装好了
npm
npm install原理
- package.json与package-lock.json版本号不一样,优先package.json,再去更新lock文件
- 若一致检查是否有缓存
当A与B使用同一个版本的C,可以将C 提到一级模块下面,A B可以复用C模块(扁平化)
当A与B使用不同版本的C,不可以扁平化,需要单独安装依赖
发布npm包
好处:使用npm包就可以方便的管理并对版本进行控制
步骤
- 创建账号:npm adduser
- 登录账号npm login (通过npm get registry 检查是否为npm官方源否则无法使用)
- 发布 npm publish
注:同版本的不能重复再发,别人发过的不能再发
搭建私服
好处:
- 可以离线使用,将npm 私服部署到内网集群
- 提高包的安全性
- 提高包的下载速度
npx
作用:在命令行中运行node 包里可运行文件 node_modules下面.bin的可执行文件
npm与npx区别
- npx侧重于执行命令的,执行某个模块命令,虽然会自动安装模块但重在执行
- npm侧重安装或写在某个模块,重在安装,并不具备执行某个模块的功能
模块化
CommonJS规范
引入模块(require)支持四种格式:
- 支持引入
httposfschild_process等nodejs内置模块
const fs = require('node:fs') //高版本 nodejs:fs 低版本:fs
console.log(fs)
- 支持引入第三方模块:
expressmd5koa
const md5 =require('md5')
console.log(md5('1234567'))
- 支持引入自己编写的模块 ../../
require('./test.js')
- 支持引入addon C++扩展模块 .node文件
- 支持引入json文件
const data = require('./data.json')
console.log(data,1)
导出
module.exports = {
success:1,
error:0,
esm 不支持引入json文件
高版本可以强行使用,代码如下
import json from './data.json' assert {type:"json"}
console.log(json)
Cjs和ESM 区别
-
Cjs是基于运行时的同步加载,esm是基于编译时的异步加载
-
Cjs可以修改值,esm不可
-
Cjs不可以tree shaking,esm支持
-
commonjs中顶层的this指向这个模块本身,而ES6中顶层this指向undefined
动态引入
import ('./test.js').then(res=>{
console.log(res.name)
})
}
源码下载
nodejs的官网——其他版本——源代码
fs模块读写操作文件
什么是fs文件系统模块
fs 模块是Node.js官方提供的、用来操作文件的模块。它提供了一系列的方法和属性,用来满足用户对文件的操作需求。
例如:
- fs.readFile()方法,用于读取指定文件中的内容。
- fs.writeFile()方法,用于向执行的文件中写入内容
如果要在javascript代码中使用fs模块来操作文件,则需要使用如下的方式先导入它:
const fs = require('fs')
全局变量
1.在node环境中没有window相关概念,无DOM和BOM
2.浏览器端使用window
3.node中使用global
4.globalThis通过浏览器环境自动判断
5.ECMAScript中大部分都可以使用
global 定义全局变量
存在访问顺序:
- require在global上方访问不到 undefined
- require在global下方可以进行访问
node环境内置API
- dirname
console.log(__dirname) //获取当前文件所在目录
//是绝对路径
- filename
console.log(__filename)
//获取当前文件的绝对路径
- Buffer
- process
console.log(process.argv)
//获取当前执行进程中的参数
杀死当前进程
setTimeout(()=>{
console.log('结束')
},5000)
监听进程被杀死的事件
setTimeout(()=>{
process.exit()
},2000)
process.on('exit',()=>{
)
CSR SSR SEO
jsdom 模拟浏览器环境的库 可以在Node.js中使用 DOM API
1.首先安装这个库
npm i jsdom
SSR :服务端渲染
CSR :客户端渲染 vue react SPA(单页面应用)
CSR和SSR区别
- 页面加载方式
- CSR首次渲染很慢,SSR并非如此
- 内容生成
- CSR使用JS去动态生成
- SSR 大部分由服务端已经预先渲染好了
- 用户交互和体验
- SSR是提前把内容加载好,对SEO(搜索引擎优化)更友好
SEO (TDK)
- T:tittle
- D:description 描述
- K:keyworld 关键词
应用场景
CSR应用:ToB后台管理系统 (不需要很高的SEO支持) SSR应用:密集型应用大部分是ToC新闻网站,博客网站
Path
posix
posix:表示可移植操作系统的接口
- baename 返回给定路径的最后一部分
路径最后一部分为xm 所以返回为xm.html
windows系统兼容正反斜杠 但posix处理不了windows的路径
const path = require('node.path')
console.log(path.basename('\\foo\\bar\\baz\\asdf\\xm.html'))
- dirname
dirname:返回路径的目录名(与basename互补)
console.log(path.basename('\\foo\\bar\\baz\\asdf\\xm.html'))
返回 \foo\bar\baz\asdf
- extname 返回路径的扩展名 .html(返回值是带点的)
consle.log([path.extname('index.js')])
返回值为 .js
如果没有点,返回的就是空的
如果有多个点,返回最后一个
consle.log(path.extname('index.a.a.a.a..xmsb'))
返回值为 .xmsb
path.join() 拼接路径
consle.log(path.join('/a','/b','/c'))
返回值 :\a\b\c
path.resolve() 解析路径 返回的是绝对路径
- 都是绝对路径,返回最后一个
consle.log(path.resolve('/a','/b','/c'))
//返回 F:\c
- 只有一个相对路径,返回当前工作目录的绝对路径
consle.log(path.resolve('.index.js'))
//返回 F:\project\node
- 绝对路径+相对路径 返回一个绝对路径
consle.log(path.resolve(__dirname,'./index.js'))
////返回 F:\project\node\index.js
path.parse() 解析路径返回一个对象
console.log(path.parse('/home/user/dir/file.txt'))
//{
//root:'/', 根目录
//dir:'/home/user/dir', 文件所在目录
//base:'file.txt',文件名+后缀名
//ext:'.txt', 后缀名
//name:'file' 文件名
//}
返回值为对象:
path.format() 解析对象返回一个路径
console.log(path.format(
{
root:'/',
dir:'/home/user/dir',
base:'file.txt',
ext:'.txt',
name:'file'
}
))
返回为路径
path.sep
- windows 返回\
- posix 返回/
console.log(path.sep)
OS
常用API
- platform 获取操作系统平台 win32 windows darwin mac linux
console.log(os.platform())
- release 获取操作系统版本
console.log(os.release())
- type 直接输出操作系统
console.log(os.type())
- version 可以区分家庭版 专业版 旗舰版等
console.log(os.version())
open打开浏览器的实现原理:
判断不同的操作系统 分别调用对应的shell命令
const os = require('node:os')
const {exec} = require('child_process')
//exec 可以执行shell命令
const plaform = os.plaform()
const open = (url)=>{
//mac
if(platform === 'darwin'){
exec('open ${url}')
//windows
}else if(platform === 'win32'){
exec('start ${url}')
//linux
}else if(platform === 'linux'){
exec('xdg-open ${url}')
}
}
open('http://www.baidu.com')
跳转至百度
homedir 读取用户所在目录
底层原理:
- %userprofile%
- mac $HOME
console.log(os.homedir())
arch获取cpu架构
console.log(os.arch())
获取操作系统线程 cpu信息
console.log(os.cpus().length)
获取网络信息
console.log(os.networkInterfaces())
process
process 是Node.js操作当前进程和控制当前进程的API,并且是挂裁到globalThis下面的全局API
API介绍
- proces.arch
返回操作系统CPU架构,与之前os。arch一样
console.log(process.arch)
platform也与os相同
console.log(process.platform)
- argv 返回数字
console.log(process.argv,process.argv.includes('--version')?'1.0.0','无')
- cwd() 获取工作目录
- 获取绝对路径
- esm模式下用不了__dirname 可以使用cwd代替
console.log(process.cwd())
4.memory usage 性能优化,获取内存里的信息
返回的是一个对象
console.log(process.memoryUsage())
// {
// rss:31006720 常驻集大小,物理内存的存量
// heapTotal:6438912, v8给我们分配的堆内存的总大小 包括未使用的内存
// heapsed:5679584, 已经使用的内存
// external:423221, 外部的内存 C C++使用的
// arrayBuffer:17606 二进制的总量
// }
- exit 退出进程
setTimeout(()=>{
console.log(5)
},5000)
process.on('exit',()=>{
console.log('进程退出了')
})
setTimeout(()=>{
process.exit()
},2000)
//2秒钟就已经执行了,5秒的不会执行
- kill 杀死进程 需要一个参数pid 进程id
setTimeout(()=>{
console.log(5)
},5000)
setTimeout(()=>{
process.skill(process.pid)
},2000)
kill与exit效果一样
- env环境变量
- 获取操作系统所有的环境变量
- 修改只在当前进程生效,不会真正影响系统的环境变量
console.log(process.env)
可以区分开发环境 生产环境
下载一个第三方库
npm i cross-env
输入代码
console.log(process.env.NODE_ENV== 'dev' ? '开发环境':'生产环境')
//跨平台的windows SET 环境变量
//posix export 设置环境变量
child_process
child_process 子进程:
- 子进程是Node.js核心API
- 一个API后面加sync就是同步的方法
- 不加为异步 回调函数返回一个buffer
- exec
- 帮我们执行shell命令或者和软件进行交互
- 适用于执行较小的shell命令 如:想要立马拿到结果的shell 就适合execSync
- 缺点:有字节上限 超过200KB就会报错
//异步的方法
exec('node -v',(err,stdout,stderr)=>{
if(err){
return err
}
console.log(stdout.tostring())
})
//同步(更简单)
const nodeVersion = execSync('node -v') //buffer
console.log(nodeVersion.tostring())
打开浏览器
execSync('star chrom http://www.baidu.com')
2.spawn
- 没有字节上限 因为他返回是个流
- spawnSync使用比较少
const {stdout} =spawn('netstat')
stdout.on('data',(msg)=>{
console.log(msg.tostring())
})
stdout.on('close',(msg)=>{
console.log('结束了')
})
传参:
const {stdout} =spawn('netstat',['-a'])
stdout.on('data',(msg)=>{
console.log(msg.tostring())
})
stdout.on('close',(msg)=>{
console.log('结束了')
})
不仅输出TCP还输出UDP
spawn和exec都可以接收options(配置相同)
exeFile 作用:执行可执行文件
底层实现顺序:
exec->execFile ->spawn
3.fork 只接收js模块
- 可以把耗时的放入子进程内执行,执行完后再让子进程吐出来
- 子进程给主进程发信息
- 通讯依靠IPC完成,IPC基于libuv去做的
ffmpeg
主要功能:
- 格式转换
- 视频处理
- 音频处理
- 流媒体传输
- 视频处理效率高
- 跨平台支持
下载地址:www.ffmpeg.org/download.ht…
并且在环境变量中进行配置:
在系统变量中的Path里添加下载后的bin的文件地址。
最后通过ffmpeg -version来检查是否安装完成
- 基本格式转换
- 提取视频中的音频
- 裁剪视频
-ss 10 -to 20 - 加水印 -vf
- 删除水印
events
Nodejs事件采用了 :发布订阅设计模式
用法和vue2 event bus第三方库 mitt相同 都采用发布订阅模式
发布订阅模式
- off:删除事件
- on:订阅事件
- emit :发布事件
- once:触发事件
const eventEmitter = require('events')
const bus = new eventEmitter()
//订阅一个事件 名字随便起
bus.on('test',(neme)=>{
console.log(name)
})
//发布
bus.emit('test','lmd')
不管使用多少次 once只会打印一次,使用emit就会打印两次
bus.on('test',fn)
//默认监听10个事件,超出则会报错
util
util promisy
- kCustomPromidifyArgsSymbol 没有对外提供
util.callbackify
将 async 异步函数(或者一个返回值为 Promise 的函数)转换成遵循异常优先的回调风格的函数
例如将 (err, value) => ... 回调作为最后一个参数。 在回调函数中,第一个参数为拒绝的原因(如果 Promise 解决,则为 null),第二个参数则是解决的值
const fn = (type) => {
if(type ==1){
return PromiseRejectionEvent.resolve('success')
}else{
return PromiseRejectionEvent.resolve('error')
}
}
const callback = util.callbackify(fn)
callback(1,(err,value)=>{
console.log(err.value)
})
通过pop可以毒打最后一个回调函数
成功:null和res
失败:err
original 为 async 异步函数。该函数返回传统回调函数
util.format()
- 类似于C的printf
- %s匹配字符,对应第一个参数
console.log(util.format('%s---%s','xm','zs'))
pegquant
- 0-100 数字越高 质量越好 体积越大 数字越小 质量月底 体积更小
- 1-10 数字越小越慢 但是质量高 越大越快
fs
fs分类
fs文件系统共有三个版本:异步(不加sync)、同步、promise
1.异步
fs.readFile('./index.txt',{
encoding:'utf-8', //编码
flag:'r'
},(err,data)=>{
if(err)throw err
console.log(data)
})
2.同步
//同步方式会阻塞代码
let result = fs.readFileSync('./index.txt')
console.log(result)
console.log('test')
3.promise
fs.readFile('./index.txt').then(result=>{
console.log(result.tostring("utf-8"))
})
fs.watch():可以监听到文件在发生变化
fa.watch('./index.txt',(event,filename)=>{
console.log(event,filename)
})
异步的方式:
1.fs的IO操作都是由libuv完成的
2.完成任务之后才会推入v8的事件队列
使用
1.写入文件
const fs = require('node:fs')const fs = require('node:fs')
fs.writeFileSync('./index.txt','lmd ')
//第一个为写入文件的路径 第二个为内容(字符串)
//修改第二个内容后 直接进行替换 若要替换则是如下样式
const fs = require('node:fs')
fs.writeFileSync('./index.txt','lmd ',{
flag:'a'
})
//第一个为写入文件的路径 第二个为内容(字符串)
追加内容:
fs.appendFileSync('./index.txt','\llllll')
2.创建可写流
let writeStream = fs.createWriteStream('./index.txt')
let verse = [
'1111111111',
'2222222222',
'3333333333',
'4444444444'
]
verse.forEach(item =>{
writeStream.write(item + '\n')
})
writeStream.end()
//要关闭通道 否则就会一直打开
writeStream.on('finish',()=>{
console.log('写入完成')
})
- 软连接 硬链接 pnpm 底层原理
//原始地址 硬链接之后的地址
fs.linkSync('./index.txt','./index2.txt')
//txt1和2共享一个内存空间
//硬链接 共享文件 备份文件
原始文件删除 不受影响
软链接很像windows的快捷方式 受原始文件影响
fs.symlinkSync('./index.txt','index3.txt')
//需要管理员权限
crypto
crypto 模块的目的是为了提供通用的加密和哈希算法,是nodejs中内置的一个密码学模块
分类
- 对称加密
- 非对称加密
- 哈希函数
对称加密
双方协商定义一个密钥以及iv
- 第一个参数 algorithm 接受一个算法 aes-256-cbc
- 第二个参数 key 也就是密钥 32位
- 第三个参数 iv初始化向量 支持16位 24位 32位(iv作用:保证我们生成的密钥串每次是不一样的,若密钥缺少位数还可以进行补码)
加密的用法:
const crypto = require('node:crypto');
let key =crypto.randomBytes(32);
let iv = Buffer.from(crypto.randomBytes(16));
const cipher = crypto.createCipheriv("aes-256-cbc",key,iv)
cipher.update('小满zs',"utf-8","hex")
const result = cipher.final("hex") //输出密文 16进制
console.log(result);
解密 相同的算法 相同的key 相同的iv
非对称加密
- 公钥:对外开放
- 私钥:管理员拥有
const {privateKey,publicKey} = crypto.generateKeyPairSync('rsa',{
modulusLength:2123,
})
//公钥加密
const encrypted = crypto.publiccrypt(publicKey,Buffer.from('德哥lmd'))
console.log(encrypted.toString('hex'))
//私钥解密
const decrypted =crypto.privateDecrypt{privateKey,encrypted}
console.log(decrypted.toStirng())
哈希函数
const crypto = require('node:crypto');
let hash = crypto.createHash('sha256')//md5
hash.update('德哥')
// 计算哈希值,并以十六进制字符串形式输出
console.log(hash.digest('hex'))
特点:
- 单向 不可逆,不可被解密
- 具有唯一性:具有较低碰撞概率
使用场景:
- 我们可以避免明文传输 使用md5加密或者sha256
- 读取文件内容 转换成md5 上传给服务端
脚手架
编写脚手架
- 自定义命令
- --V --help creae 命令交互工具
- 下载isTs下载ts版本
markdown 转html工具
EJS
官网:ejs.co/
中文站:ejs.bootcss.com/
- 纯脚本标签
<% alert('hello world') %>
marked
编写一个简单的md文档
### 标题
-test
将md转换成html
const marked =require('marked')
marked.parse(readme.toString())//调用parse即可
browserSync
创建browserbingqie 开启一个服务设置根目录和index.html文件
zlib
Gzip
const zlib = require('node:zlib')
const fs = require('node:fs')
//压缩createGzip
const readStream = fs.createReadStream('index.txt')
const writeStream = fs.createWriteStream('index.txt.gz')
readStream.pipe(gzip).pipe(writeStream)
//解压createGunzip
const readStream = fs.createReadStream('index.txt.gz')
const writeStream = fs.createWriteStream('index2.txt')
readStream.pipe(zlib.createGunzip()).pipe(writeStream)
deflate
const zlib = require('node:zlib')
const fs = require('node:fs')
//压缩 createDeflate
const readStream = fs.createReadStream('index.txt')
const writeStream = fs.createWriteStream('index.txt.deflate')
readStream.pipe(gzip).pipe(writeStream)
//解压 createDeflate
const readStream = fs.createReadStream('index.txt.deflate')
const writeStream = fs.createWriteStream('index3.txt')
readStream.pipe(zlib.createInflate()).pipe(writeStream)
区别:
- Gizp慢于Deflate
- Gizp:适用于文件压缩
- Deflate:适用于文件传输
http
web服务器
const http = require ('node:http')
const url = require('node:url')
//req 接受前端的信息 res 给前端返回的信息
http.createServer((req,res)=》{
if(req.method==='POST'){
res.end('POST')
}else if(req.method==='GEYT')
res.end('GET')
}).listen(98,()=>{
console.log('98端口启动成功')
})
反向代理
安装库
npm install http-proxy-middleware
动静分离
区分动态资源(API请求,动态网页)和静态资源(html,css,Javascript,图像文件)
通过库自动给分析类型,不用自己手写文件
npm i mime
邮件服务
端口号默认为80
- 安装 用的库
npm install yaml
npm install nodemailer
- 引入
import nodemailer from 'nodemailer'
import yaml from 'js-yaml'
import http from 'node:http'
import fs from 'node:fs'
import url =from 'node:url'
const mailInfo = yaml.load(fs.readFileSync('./mail.yaml','utf8'))
//初始化邮件服务
const transport = nodemailer.createTransport({
service:'qq', //服务商
host:'smtp.qq.com',
port:465,
secure:true,
auth:{
user:'', //邮箱账号
pass:'', //密码 授权码
}
})