NodeJS
REPL
read-eval-print-Loop
Node程序传递参数
执行 node程序
- node index.js
传递参数 通过process 来获取
node index.js env=development xxx
- javascript
console.log(process.argv[2])//{env:development} console.log(process.argv[3]) //xxxx console.log("weweewew") console.trace() //打印函数调用栈
Node全局对象
- process / console / 定时器 setTimeout setInterval setImmediate
- clearInterval clearTimeout clearImmediate 对应的清除事件
- process.nextTick
- 下个进程执行
- setImmediate
- 立即执行
特殊的全局对象【模块对象】
dirname / filename / require /export
不可以在repl 中使用
- __dirname
- 当前文件所在目录名称
- __filename
- 当前文件所在目录名称
gobal与window的区别
- node 定义变量不会被挂载到 gobal
- window 定义全局变量 会被挂载到window ** process 挂载全局 通过 Object.defineProperty()实现**
模块化
javascript 被称为 披着C语言外衣的 Lisp 人工智能方面 模块化规范 esModule AMD CMD node 模块化 基于 CMD 也是实现了 esModule
CommonJs
在浏览器之外使用的地方 【被称为serverJs】 在浏览器中使用 CJS【commonJs】 Node Browserify webpack 支持 CJS
规范核心变量
- exports【没什么鸟用 为了迎合规范】
- exports === module.exports
- exports是 module.exports 的引用
- module.exports
- 当 module.exports 定义为一个新的对象 将会开辟一个新的内存空间 则moudle.exports != exports
- exports === module.exports
- require【加载过程同步的】
- path、 http 的核心模块【?】
- 以 ‘./’ or '../' or '/'【根目录】 开头
- 有后缀 直接找对应的文件
- 无后缀 找文件 X > X.js > X.json > X.node 以此查找;
- 默认找 index.js > index.json >index.node
- other 报错
- 并不是一个核心模块
- 逐级往上查找 node_modules/xxx/index
- 多次加载 仅会加载一次【缓存】
- module.loaded 判断是否被加载了 boolean
- 按分支加载到 最底层 再查找其他分支【图结构】深度优先查找, 则是mian>aaa>ccc>ddd>eee>bbb
- CommonJs缺陷
- 同步加载
AMD 【异步模块定义 Async Module define】
require.js
- javascript
<script src="./lib/require.js" data-main="./index.js"></script> //加载完成 require.js 立即加载 index.js
index.js 定义 模块
CMD[Common Module define]
异步加载模块 【很少用】
ES Module
export import 关键字
自动采用严格模式
- javascript
<script type="module" src="./modules/foo.js"></script> //modeule
- javascript
// 导出 //default可以 不写名称 导入名称可以是任意值 export default foo = { name: 'foo', age:'12' } //按需导出 export const name ="foo" const name = "foo" // {} 不是对象 export { name as foo }
//导入 import { foo } from "./foo"; // 别名 import { foo as name } from "./foo"; // * as import * as foo from "./foo";
export 与 import 结合使用
export {name,xx,xxx} from "pathxxx"
先从pathxxx import {name,xx,xxx} 然后导出 {name,xx,xxx}
封装统一入口 比如 n多个 api.js 所有都在index.js 中做统一导出
import函数
- import函数 传递path ,返回值是一个promise then catch
- 例如:
import('./xxx') .then(res=>{consloe.log(res)}).catch(error=>console.log(res))
ESModule加载过程
- 解析是加载
- 异步
ESModule 和 CommonJS交互【互相加载】
- 通常情况CommonJS不能加载 ESModules;CommonJS同步加载 ESModule 异步加载
- ESModule 可以加载 CommonJS
内置模块
path
js
const path = require('path');
const path1 = '/User/yhx'
const path2 = 'abc.txt'
// 路径拼接
const completedPath = path.resolve(path1, path2)
console.log('完整路径', completedPath) //完整路径 E:\User\yhx\abc.txt
// 获取文件基础路径
const basePath = path.dirname(completedPath)
console.log('文件基础路径', basePath)//文件基础路径 E:\User\yhx
// 获取文件名
const fileName = path.basename(completedPath)
console.log('文件名', fileName)//文件名 abc.txt
// 获取文件扩展名
const extName = path.extname(completedPath)
console.log('文件扩展名', extName)//文件扩展名 .txt
// 通过 json实现路径拼接
const path3 = path.join(path1, path2)
console.log('路径拼接', path3) // 路径拼接 \User\yhx\abc.txt
// 与 path.resolve 与 path.join 区别
// 1以 '/' './','../' 开头 resolve 会携带 父级到根目录
// 获取当前文件目录
console.log('__dirname', __dirname)
fs[file System 文件系统]
fs三种文件的获取
js
/**
* API 大多有三种操作方式
* 方式1:同步操作文件:代码会被阻塞
* 方式2:异步回调操作文件:需要传入回调函数 调用回调 获取结果
* 方式3:异步Promise :返回Promise 通过 then catch 来处理
*/
const fs = require('fs')
const filePath = "./abc.txt"
// 方式1 同步通过操作
const getFileStatus1 = fs.statSync(filePath)
console.log('获取文件', getFileStatus1)//获取文件
/**
* Stats {
dev: 4031650434,
mode: 33206,
nlink: 1,
uid: 0,
gid: 0,
rdev: 0,
blksize: 4096,
ino: 281474978062517,
size: 17,
blocks: 0,
atimeMs: 1694870024431.592,
mtimeMs: 1694870024431.592,
ctimeMs: 1694870024431.592,
birthtimeMs: 1694870007769.3984,
atime: 2023-09-16T13:13:44.432Z,
mtime: 2023-09-16T13:13:44.432Z,
ctime: 2023-09-16T13:13:44.432Z,
birthtime: 2023-09-16T13:13:27.769Z
}
*/
// 方式2 异步获取
// const getFileStatus2 =
fs.stat(filePath, (err, data) => {
console.log('err', err)
console.log('data', data)// 同上
})
// console.log('getFileStatus2', getFileStatus2);
// 方式3 异步Promise
fs.promises.stat(filePath).then(res => {
console.log('res', res);// 同上
}).catch(err => console.log(err))
文件描述符
简单的数字标识符
文件的读写
flag
js
/**
*
*
*/
const fs = require('fs')
const filePath = "./abc.txt"
const content = "hello world 我是 hello World"
/**
* 1文件写入
* @param{filePath, content,options:{flag:""},callback}
*
*/
fs.writeFile(filePath, content, (err) => {
console.log(err);//null error
})
// 注意读取写入 不要同时使用
// 2读取文件
fs.readFile(filePath, { encoding: 'utf-8' }, (err, data) => {
console.log('data', data)//data hello world 我是 hello World
})
encoding 选项
文件夹操作
js
/**
* 文件夹的操作
* 1.创建文件夹
* 2.读取文件所在文件的所有文件
* 3.文件夹的重命名
*/
const fs = require('fs')
const path = require('path')
const filePath = "./测试文件夹"
// 判断文件是否存在
console.log('fs.Directory.exists(filePath)', fs.existsSync(filePath))
if (!fs.existsSync(filePath)) {
// 1.创建文件夹
fs.mkdir(filePath, (err) => {
console.log('err', err)
})
}
// 2.读取文件所有文件
// 封装获取文件在所有内容文件
const getFiles = (filePath, result) => {
return new Promise((resolve, reject) => {
fs.promises.readdir(filePath, { withFileTypes: true }).then(files => {
files.forEach(file => {
result.push(file.name)
if (file.isDirectory()) {
getFiles(path.resolve(filePath, file.name), result)
}
})
files.filter(file => file.isDirectory()).length === 0 && console.log(result) && resolve(result)
})
})
}
// 深层的await return
getFiles(filePath, []).then(res => {
console.log('res', res);
})
// fs.readdir(filePath, { withFileTypes: true }, (err, files) => {
// files.forEach(file => {
// console.log('是否是个文件夹', file.isDirectory());
// console.log('是否是文件', file.isFile())
// console.log('文件名', file.name);
// })
// })
// 3.文件夹的重命名
if (!fs.existsSync('./测试文件夹/testReName')) {
fs.rename("./测试文件夹/test", "./测试文件夹/testReName", (err) => {
console.log('err', err)
})
}
// 4.文件的复制
fs.copyFile('./测试文件夹/testReName/tr01.txt', './测试文件夹/testReName/tr02.txt', (err) => {
console.log('err', err);
})
events 模块
常用方法
js
const EventEmitter = require('events');
// 1.创建一个emitter 发射器
const emitter = new EventEmitter()
// 2.监听某个事件
// addListener 是 on alias简写
// on alias
const listener = (arg) => {
console.log('msg', arg)
}
emitter.on('login', listener)
// 3.发射login事件
emitter.emit('login', 'hello world')
// 4.取消监听
emitter.off('login', listener)
获取信息
js
const EventEmitter = require('events');
// 1.创建一个emitter 发射器
const emitter = new EventEmitter()
// 2.监听某个事件
// addListener 是 on alias简写
// on alias
const listener = (arg) => {
console.log('msg', arg)
}
emitter.on('login', listener)
emitter.on('tap', listener)
// 3.发射login事件
emitter.emit('login', 'hello world')
// 获取注册事件
console.log('获取注册事件', emitter.eventNames()) //获取注册事件 [ 'login', 'tap' ]
//
console.log('获取事件发生次数', emitter.listenerCount('login')) //获取事件发生次数 1
console.log('获取文件listener', emitter.listeners('login')) //获取文件listener [ [Function: listener] ]
不常用方法
js
const EventEmitter = require('events');
// 1.创建一个emitter 发射器
const emitter = new EventEmitter()
// 2.监听某个事件
// addListener 是 on alias简写
// on alias
const listener = (arg) => {
console.log('msg', arg)
}
emitter.once('login', listener) //仅仅监听一次
emitter.prependListener('click', listener) //添加一个监听放在最前面
emitter.prependOnceListener('click', listener) //添加一个监听放在最前面 并且只监听一次
emitter.removeAllListeners() //移出所有监听器
包管理工具
常见属性
script属性
- 键值对形式存在
dependencies属性
- 无论生产环境和开发环境都需要的依赖包
devDependencies属性
- 仅在开发环境下使用的依赖 -S
-save
版本号规则
^x.y.z
或~x.y.z
^x.y.z
:表示x不变 ,y、z永远安装最新的~x.y.z
:表示x、y不变, z永远是最新的
engines属性
- 用于指定 Node 与NPM 版本
browserList属性
- 兼容浏览器 添加补丁
npm install 命令
- -g 全局安装
- 缓存策略
npx
- 调用项目中的某个模块指令
- npx axios -V
实现脚手架
指令生效
1.【index.js】#!/usr/bin/env node
//自动执行 配置node路径 shebang
2.【package.json】 "bin": {
"yhx": "index.js"//全局指令名称 执行文件名称
}
3.终端运行 npm link ,配置到环境变量中
4.Commander.js 指令开发 --version --help 等
- javascript
脚手架上传
- 1 npm 注册
- 2 npm login 【登录 按提示操作】
- 3 编辑 package.json [keywords],homepage repository :{ type :'git', url:'地址' }
- 4 npm publish
Buffer 和 二进制
js
const msg = "Hello world!";
// 创建方式1
// const buffer = new Buffer(msg);
// 创建方式2 content , 编码格式(默认utf8)
const buffer = Buffer.from(msg);
// 16进制 展示
console.log("编码", buffer); //<Buffer 48 65 6c 6c 6f 20 77 6f 72 6c 64 21>
// 解码 toString 默认 utf8
console.log("解码", buffer.toString()); //Hello world!
// 创建方式3 参数 字节数量
const buffer2 = Buffer.alloc(10);
console.log("创建方式3", buffer2); //创建方式3 <Buffer 00 00 00 00 00 00 00 00 00 00>
// 修改 buffer2
buffer2[0] = 80;
buffer2[1] = 65;
console.log("修改", buffer2); //修改 <Buffer 50 41 00 00 00 00 00 00 00 00>
const fs = require("fs");
// 读取文件 txt
fs.readFile('./txt.txt', function (err, data) {
console.log('.txt:data', data)//data <Buffer e6 9d 8e e7 8b 97 e8 9b 8b>
})
// 读取png文件
fs.readFile('./png.png', function (err, data) {
console.log('png:data', data)//png:data <Buffer 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 00 00 06 b0 00 00 02 ad 08 06 00 00 00 6f d5 2e 71 00 00 20 00 49 44 41 54 78 9c ec 9d d7 92 e3 d6 96 ... 372956 more bytes>
})
// 实现 图片的截取
// sharp 使用
/**
* 不要在浏览器环境使用
* const sharp = require("sharp");
sharp('./png.png').resize(200, 200).toBuffer().then(function (data) {
fs.writeFile('./pngsharp.png', data, (err) => {
if (err) {
console.log('err', err)
}
});
})
*/
// 创建buffer 申请内存时 默认大小8kb(内存池) 并不会频繁地申请内存 直到耗光 8kb,申请下一次内存
Stream
js
/**
* Stream流
*/
const fs = require('fs');
const reader = fs.createReadStream('./foo.txt', {
start: 3,
end: 6,
highWaterMark: 2
})
// 读取文件
reader.on("data", (data) => {
console.log(data);
setTimeout(() => {
reader.resume();
},1000)
})
// 监听开启
reader.on('open', (data) => {
console.log('文件被打开了');
})
// 监听关闭
reader.on('close', (data) => {
console.log('文件被关闭了 ' );
})
//传统写入方式
fs.writeFile('./foo.txt', 'hello world foo', (err) => {
if (err) {
console.log(err);
}
})
// 写入文件
const writer = fs.createWriteStream('./foo.txt',{flags:'a',start:4})
writer.write('你好啊', (err) => {
if (err) {
console.log(err);
}
})
//写入完成 同时关闭流
writer.end('追加到最后')
writer.on('close', (data) => {
console.log("文被关闭");
})
js
const fs = require('fs');
// 传统写法
// fs.readFile('./pip.txt', (err) => {
// if (err) {
// console.log(err);
// } else {
// fs.writeFile('./pip.txt', 'Hello world', (err) => {
// if (err) {
// console.log(err);
// } else {
// console.log('写入成功');
// }
// })
// }
// })
// Stream 的写法
const writer = fs.createWriteStream('./pipe/pipewrite.txt');
const reader = fs.createReadStream('./pipe/pipereader.txt');
// 将读取的流 写入新的文件
reader.pipe(writer)
// writer.close()
http 开发web服务器
创建方式
js
const http = require('http')
/**
*
* 两中创建方式
* 1.new http.Server
* 2.http.createServer()
* 本质一样的
*/
const server1 = new http.Server((req, res) => {
res.end('server1')
})
server1.listen(8081, '0.0.0.0', () => {
console.log('8081 启动成功');
})
const server2 = http.createServer((req, res) => {
res.end('server2');
})
// 0.0.0.0 监听IPV4 的所有值 默认值 也是 IPV4:0.0.0.0 IPV6 :::
server2.listen(8082, '0.0.0.0', () => {
console.log('8082 启动成功');
console.log(server2.address().port); //获取端口
})
/**
* 监听方法使用
*/
js
const http = require('http');
/**
* 开发web服务器
*/
// 创建一个服务器
const server = http.createServer((req, res) => {
res.end('hello change');//添加并关闭 返回数据
})
// 配置端口号,postname callback
server.listen(8888, '0.0.0.0', () => {
console.log('服务器已成功开启~');
})
/**
* nodemon 文件变化直接重启
*/
request对象
js
const http = require('http');
const url = require('url');
const qs = require('querystring'); //处理请求query
const server = new http.Server((req, res) => {
// console.log('url', req.url);
// console.log('method', req.method);
// console.log('headers', req.headers);
// 解析参数
const { pathname, query } = url.parse(req.url)
if (pathname === '/login') {
const { username,password}= qs.parse(query)
res.end(`username:${username}\npassword:${password}\n请求方式:GET`)
}
// post请求方式
else if (req.method === 'POST') {
if (pathname === "/post") {
// 拿到data body
req.setEncoding('utf8') // set
req.on('data', (data) => {
// console.log(data.toString); //二进制转 utf8
const { username,password} = JSON.parse(data)
res.end(`username:${username}\npassword:${password}\n请求方式:POST`)
})
}
} else {
res.end('end login')
}
})
server.listen(8080, '0.0.0.0', () => {
// request 对象封装了 传递给服务器的信息
console.log("server服务器已成功开启");
})
headers
js
const http = require('http')
/**
* header 属性
* content-type :携带的数据类型
* applicant/json:json
* text/plain :文本
* application/xml:xml
* multipart/form-data :上传文件
*/
/**
* header 属性
* content-length :文件大小和长度
*/
/**
* header 属性
* connection:keep-alive
* http 基于TCP 协议 通常进行请求响应结束后 立即中断
* Node 中默认是 5s
* 服务端保持时间不同
*/
/**
* header 属性
* accept-encodeing :告知服务器 客户端支持 的文件压缩格式 例如 js 压缩成 gzip 编码,对应文件格式 .gz
*
*/
/**
* header 属性
* accept :告知服务器接受文件格式类型
*
*/
/**
* header 属性
* user-agent :客户端相关信息
*
*/
const server = new http.Server((req, res) => {
res.setHeader('Content-Type', 'application/json')
console.log(req.headers);
res.end('end')
})
server.listen(8080, '0.0.0.0', () => {
console.log("8080 端口已开启");
})