Node js

449 阅读13分钟

概述

  1. 什么是node.js

Node js 是javascript运行时的环境而非编程语言

  1. Node.js中的JavaScript运行环境

NodeJs中分为两部分,一部分是V8引擎为了解析和执行JS代码。另一部分是内置API,内置API提供了一些能力,让我们JS能调用这些API完成一些后端执行的事情。

Node js单线程,适合IO密集性应用

Node.js中无法调用DOM和BOM等浏览器内置API

安装

安装LTS版本(长期维护版)

下载地址:www.nodejs.com.cn/

image.png

此时说明已经安装好了

npm

npm install原理

image.png

  • package.json与package-lock.json版本号不一样,优先package.json,再去更新lock文件
  • 若一致检查是否有缓存

image.png

当A与B使用同一个版本的C,可以将C 提到一级模块下面,A B可以复用C模块(扁平化)

image.png

当A与B使用不同版本的C,不可以扁平化,需要单独安装依赖

发布npm包

好处:使用npm包就可以方便的管理并对版本进行控制

步骤

  1. 创建账号:npm adduser
  2. 登录账号npm login (通过npm get registry 检查是否为npm官方源否则无法使用)
  3. 发布 npm publish

注:同版本的不能重复再发,别人发过的不能再发

搭建私服

好处:

  1. 可以离线使用,将npm 私服部署到内网集群
  2. 提高包的安全性
  3. 提高包的下载速度

npx

作用:在命令行中运行node 包里可运行文件 node_modules下面.bin的可执行文件

npm与npx区别

  • npx侧重于执行命令的,执行某个模块命令,虽然会自动安装模块但重在执行
  • npm侧重安装或写在某个模块,重在安装,并不具备执行某个模块的功能

模块化

CommonJS规范

引入模块(require)支持四种格式:

  1. 支持引入 http os fs child_process等nodejs内置模块
const fs = require('node:fs') //高版本  nodejs:fs 低版本:fs
console.log(fs)
  1. 支持引入第三方模块:express md5 koa
const md5 =require('md5')
console.log(md5('1234567'))
  1. 支持引入自己编写的模块 ../../
require('./test.js')
  1. 支持引入addon C++扩展模块 .node文件
  2. 支持引入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 区别

  1. Cjs是基于运行时的同步加载,esm是基于编译时的异步加载

  2. Cjs可以修改值,esm不可

  3. Cjs不可以tree shaking,esm支持

  4. 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 定义全局变量

image.png

存在访问顺序:

  • 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区别

  1. 页面加载方式
  • CSR首次渲染很慢,SSR并非如此
  1. 内容生成
  • CSR使用JS去动态生成
  • SSR 大部分由服务端已经预先渲染好了
  1. 用户交互和体验
  • SSR是提前把内容加载好,对SEO(搜索引擎优化)更友好

SEO (TDK)

  • T:tittle
  • D:description 描述
  • K:keyworld 关键词

应用场景

CSR应用:ToB后台管理系统 (不需要很高的SEO支持) SSR应用:密集型应用大部分是ToC新闻网站,博客网站

Path

posix

posix:表示可移植操作系统的接口

  1. baename 返回给定路径的最后一部分

路径最后一部分为xm 所以返回为xm.html

image.png

windows系统兼容正反斜杠 但posix处理不了windows的路径

const path = require('node.path')
console.log(path.basename('\\foo\\bar\\baz\\asdf\\xm.html'))
  1. dirname

dirname:返回路径的目录名(与basename互补)

console.log(path.basename('\\foo\\bar\\baz\\asdf\\xm.html'))

返回 \foo\bar\baz\asdf

  1. 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' 文件名
//}

返回值为对象:

image.png

path.format() 解析对象返回一个路径

console.log(path.format(
{
   root:'/', 
   dir:'/home/user/dir', 
   base:'file.txt',
   ext:'.txt', 
   name:'file' 
}
))

返回为路径

image.png

path.sep

  • windows 返回\
  • posix 返回/
console.log(path.sep)

OS

常用API

  1. platform 获取操作系统平台 win32 windows darwin mac linux
console.log(os.platform())

  1. release 获取操作系统版本
console.log(os.release())
  1. type 直接输出操作系统
console.log(os.type())
  1. 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')

跳转至百度 image.png

homedir 读取用户所在目录

底层原理:

  • %userprofile%
  • mac $HOME
console.log(os.homedir())

image.png

arch获取cpu架构

console.log(os.arch())

获取操作系统线程 cpu信息

console.log(os.cpus().length)

获取网络信息

console.log(os.networkInterfaces())

image.png

process

process 是Node.js操作当前进程和控制当前进程的API,并且是挂裁到globalThis下面的全局API

API介绍

  1. proces.arch

返回操作系统CPU架构,与之前os。arch一样

console.log(process.arch)

platform也与os相同

console.log(process.platform)
  1. argv 返回数字
console.log(process.argv,process.argv.includes('--version')?'1.0.0','无')
  1. 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  二进制的总量
// }

  1. exit 退出进程
setTimeout(()=>{
   console.log(5)
},5000)

process.on('exit',()=>{
   console.log('进程退出了')
})
setTimeout(()=>{
   process.exit()
},2000)

//2秒钟就已经执行了,5秒的不会执行
  1. kill 杀死进程 需要一个参数pid 进程id
setTimeout(()=>{
   console.log(5)
},5000)

setTimeout(()=>{
   process.skill(process.pid)
},2000)

kill与exit效果一样

  1. 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
  1. 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('结束了')
})

image.png

传参:

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

主要功能:

  1. 格式转换
  2. 视频处理
  3. 音频处理
  4. 流媒体传输
  5. 视频处理效率高
  6. 跨平台支持

下载地址:www.ffmpeg.org/download.ht…

并且在环境变量中进行配置:

在系统变量中的Path里添加下载后的bin的文件地址。

最后通过ffmpeg -version来检查是否安装完成

image.png

  1. 基本格式转换
  2. 提取视频中的音频
  3. 裁剪视频 -ss 10 -to 20
  4. 加水印 -vf
  5. 删除水印

events

Nodejs事件采用了 :发布订阅设计模式

image.png

用法和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'))

image.png

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('写入完成')
})
  1. 软连接 硬链接 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'))

特点:

  • 单向 不可逆,不可被解密
  • 具有唯一性:具有较低碰撞概率

使用场景:

  1. 我们可以避免明文传输 使用md5加密或者sha256
  2. 读取文件内容 转换成md5 上传给服务端

脚手架

编写脚手架

  1. 自定义命令
  2. --V --help creae 命令交互工具
  3. 下载isTs下载ts版本

markdown 转html工具

EJS

官网:ejs.co/

中文站:ejs.bootcss.com/

  1. 纯脚本标签
<% 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)

区别:

  1. Gizp慢于Deflate
  2. Gizp:适用于文件压缩
  3. 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端口启动成功')
})

反向代理

image.png

安装库

npm install http-proxy-middleware

动静分离

区分动态资源(API请求,动态网页)和静态资源(html,css,Javascript,图像文件)

通过库自动给分析类型,不用自己手写文件

npm i mime

邮件服务

端口号默认为80

  1. 安装 用的库

npm install yaml
npm install nodemailer
  1. 引入
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:'', //密码 授权码
  }
})