node 基础相关模块知识
一、先来个基础全局
创建监听80端口,服务监控请求,获取html,图片和post数据(下面是文件,图片自己找一个吧)
1.1 server.js
const http = require('http')
const server = http.createServer()
const fs = require('fs')
const url = require("url")
const querystring = require('querystring') //把2进制转成对象
server.listen('80', function () {
console.log("【监听80端口】http://127.0.0.1:80",);
})
server.on('request', function (req, res) {
if (req.method === 'GET') {
const query = url.parse(req.url, true)
console.log("query", query.query.name);
if (!/(jpg|png|jpeg)$/.test(req.url)) {
fs.readFile('./index.html', function (err, data) {
// res.setHeader("content-type","text/html;charset-utf-8")
res.end(data)
})
} else {
fs.readFile('./gezi.jpg', function (err, data) {
res.end(data)
})
}
} else if (req.method === 'POST') {
//获取客户端的传递过来的数据 req有监控data方法,也就是监控你post请求传递过来的参数
let data
req.on('data', function (d) {
console.log("~~~~~~~~~~~~~", d);
data += d
})
//监控客户端传参结束
req.on('end', function () {
console.log("option参数", querystring.parse(data));
fs.readFile('./index.html', function (err, data) {
// res.setHeader("content-type","text/html;charset-utf-8")
res.end(data)
})
})
}
})
1.2 index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.pic {
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<h1>你好啊</h1>
<img class="pic" src="./gezi.jpg" alt="" />
<form action="./" method="post">
<div><span>姓名</span><input type="text" name="username" /></div>
<div>
<span>性别</span>
<select name="age">
<option value="1">男</option>
<option value="2">女</option>
</select>
</div>
<button type="submit">提交</button>
</form>
</body>
</html>
然后在控制台输入
node server.js
二、node基础模块
2.1 path模块
新建path.mjs文件 然后
node path.mjs启动
2.1.1 path.join:
描述: 将多个路径拼接成一个相对路径 (或绝对路径,取决于第一个路径是否为根路径)
import path from "path"
console.log(path.join('a','b','c')); //a/b/c
console.log(path.join(process.cwd(),'/hello','word')) //C:\Users\admin\Desktop\node-related\node-related\nodeModel\hello\word
2.1.2 path.resolve:
描述: 将多个路径拼接成一个绝对路径,返回一个解析后的绝对路径。
console.log(path.resolve('a', 'b', 'c'))
//C:\Users\admin\Desktop\node-related\node-related\nodeModel\a\b\c
console.log(path.resolve('/hello', 'world', './a', 'b')) //\hello\world\a\b
2.1.3 path.dirname:
描述: 返回路径中的目录名。
import path from "path"
console.log(path.dirname("a/b/c.js")); // a/b
console.log(path.dirname("a/b/c")) //a/b
console.log(path.dirname(process.cwd()));
//C:\Users\admin\Desktop\node-related\node-related
2.1.4 path.basename:
描述: 返回路径中的文件名,并可选地去除给定的文件扩展名。
import path from "path"
console.log(path.basename('a/b/c.js')) //c.js
console.log(path.basename('a/b/c.js', '.js'))//c
console.log(path.basename('a/b/c.js', 'js'))//c.
console.log(path.basename('a/b/c.js', 's'))//c.j
2.1.5 path.extname:
描述: 获取路径中的文件扩展名。
console.log(path.extname('a/b/c.js')) // .js
console.log(path.extname('a/b/c')) // 无打印
console.log(path.extname('a/b/c.d.ts')) // .ts
console.log(path.extname('a/b/.npmrc')) // 无打印
2.1.5 path.parse:
描述: 用于解析文件路径,将其拆分为一个对象。
import path from "path"
console.log(path.parse('/home/user/dir/file.txt'))
//{root: '/',dir: '/home/user/dir',base: 'file.txt',ext: '.txt', name: 'file'}
2.2 fs模块
新建fs.mjs文件 然后
node fs.mjs
2.2.1 fs.readFileSync和 readFile
描述: 读取文件内容,下面分别是 3 种写法,日常开发中常用 同步操作 和 Promise形式异步操作。
fs.readFileSync(params1,params2) :
params1:设置要读取的文件路径 (相对或者绝对);
params2: 设置读取的编码格式。
fs.readFile((params1,params2,params3)
params1:设置要读取的文件路径 (相对或者绝对);
params2: 设置读取的编码格式。
params3: 回调函数。
const syncData = fs.readFileSync('./test.json', 'utf-8')
console.log(syncData); // {"name":"张三","age":18 }
// 回调 形式 异步读取
fs.readFile('./test.json', 'utf-8', function (err, data) {
if (!err) {
console.log(data); // {"name":"张三","age":18 }
}
})
// promis 写法
const data = await fs.promises.readFile('./test.json', 'utf-8')
console.log(data); // {"name":"张三","age":18 }
2.2.2 fs.writeFileSync(params1,params2,params3):
描述: 写入文件
params1:输出文件路径;
params2:输出内容;
params3 (可选):编码格式。
fs.writeFileSync('./testWrite.txt', '哈喽')
写入二进制文件 (读取一个图片,然后输出到一个新的位置)。
const imgBuf = fs.readFileSync('./rsegezi.jpg') // 返回一个二进制文件
console.log("imgBuf", imgBuf);
console.log('isBuffer', Buffer.isBuffer(imgBuf), 'bufferSize', imgBuf.length) // isBuffer true bufferSize 502770
// 写入到新文件
fs.writeFileSync('newLogo.png', imgBuf, 'binary')
2.2.3 fs.statSync:
描述: 1、通过fs.statSync 获取文件或者目录得基本信息 ;2、也可判断文件是否存在,3、判断是目录还是文件
返回的对象上还包含可直接调用的方案,用于判断文件类型。
console.log(fs.statSync('./test.json'));
const fileInfo = fs.statSync('./test.json')
console.log(fileInfo.isFile(), fileInfo.isDirectory()); // true false
const dirInfo = fs.statSync('../nodeModel')
console.log(dirInfo.isFile(), dirInfo.isDirectory()); // false true
try {
// 查询一个不存在的文件/目录信息(会抛出异常,需要自行捕获)
fs.statSync('not_exist.txt')
} catch (e) {
console.log('文件不存在')
}
2.2.4 fs.appendFileSync
描述: 追加输出,向文件末尾追加写入得内容
fs.appendFileSync('./testWrite.txt', "{ like: '排球' }")
2.2.5 fs.renameSync
描述:fs.renameSync 方法用于文件移动,当然也可以是重命名文件
fs.renameSync('./rsegezi.jpg', './rsegezi.jpg')
// 移动文件
try {
fs.renameSync('move.mjs', "path.mjs") //这里得如果第一个参数是move.mjs,第二个文件是path.mjs 那么move.mjs会被删除,path.mjs里面得内容会被move.mjs内容替换掉
} catch (e) { }
2.2.6 fs.unlinkSync 和 fs.rmSync
描述:fs.unlinkSync 和 fs.rmSync 都可用于单文件删除。 当然后者还支持删除目录,递归删除子文件/目录等
try {
fs.unlinkSync('./delete.js')// delete.js 会被删除
fs.rmSync('./delete.js')
} catch (e) { }
2.2.7 fs.readdirSync
描述:通过 fs.readdirSync 获取文件夹下所有文件信息 默认情况下只会返回名称。
console.log(fs.readdirSync("../nodeModel"));
//可通过指定第二个参数 withFileTypes:true 使返回结果包含类型。
console.log(fs.readdirSync('../nodeModel', { withFileTypes: true }));
2.2.8 fs.mkdirSync
描述 : 使用 fs.mkdirSync 创建目录,可通过设置 recursive:true 来递归创建多级目录
fs.mkdirSync("../nodeModel/create",{recursive: true })
2.2.9 fs.rmdirSync
描述 : 可以使用 fs.rmdirSync 删除目标目录,recursive: true 表明删除包含其子目录。
try {
fs.rmdirSync("./create", { recursive: true })
} catch (error) {}
2.2.10 fs.watch
描述 : 使用fs.watch 监听目录得变更
fs.watch("../nodeModel", { recursive: true }, (eventType, filename) => {
console.log(`File '${filename}' has changed: ${eventType}`)
})
2.3 util 模块
2.3.1 util.promisify(original)
描述:回调转promise;采用遵循常见的错误优先的回调风格的函数(也就是将 (err, value) => ... 回调作为最后一个参数),并返回一个返回 promise 的版本。 从而无需在函数内部使用async等待。
例子1:转换node里面的方法
const fs = require('fs')
const util = require('util')
// 将 fs.readFile() 转换为一个接受相同参数但返回 Promise 的函数。
const readFile = util.promisify(fs.readFile)
// 现在可以将 readFile() 与 await 一起使用!
const buf = await readFile('./package.json')
const obj = JSON.parse(buf.toString('utf8'))
console.log(obj.name)
例子2:自定义函数
a: 函数最后一个参数不带有回调函数的
// 测试不带回调函数的方法
const callbackFn = (a, b) => {
return a + b
}
const newCallbackFn = util.promisify(callbackFn); // 将带有回调的函数,转为返回promise对象
console.log("????newCallbackFn", newCallbackFn());//????newCallbackFn Promise { <pending> }
newCallbackFn().then((result) => {
console.log(result); // 不触发
}).catch(err => {
console.error(err);// 不触发
});
newCallbackFn返回一个等待的Promise,不会触发then 和catch函数
b:函数最后一个参数是个函数,并且在函数内调用,注意必须要调用
// 测试带有回调函数的方法
const callBackHas = (a, callback) => {
callback && callback()
}
const newCallBackHas = util.promisify(callBackHas);
newCallBackHas(2).then((res) => {
console.log("res", res); // res undefined
}).catch(e => {
console.log("err", e); // 不触发
});
为什么是undefined呢??? 因为then里面的res来源于callback的第二个参数,catch里面的e来源于callback的第一个参数,如果callback里面的第一个参数有值那么不走then,走catch,如果callback里面的第一个参数为null,那么走then;
// 测试带有回调函数的方法
const callBackHas = (a, callback) => {
callback && callback(null,12)
}
const newCallBackHas = util.promisify(callBackHas);
newCallBackHas(2).then((res) => {
console.log("res", res); // res 12
}).catch(e => {
console.log("err", e); // 不触发
});
// 测试带有回调函数的方法
const callBackHas = (a, callback) => {
callback && callback(66,12)
}
const newCallBackHas = util.promisify(callBackHas);
newCallBackHas(2).then((res) => {
console.log("res", res); // 不触发
}).catch(e => {
console.log("err", e); // err 66
});
2.3.2 util.inspect()
描述:对象转为字符串 util.inspect(object, [options]),常与 console.log 搭配使用,可以友好的将对象转为字符串,打印更加友好。
参数: depth 用于控制展开的层级
const _inspect = util.inspect({ a: "name", age: 20, c: [1, 2, 3, { name: 1, cf: () => { } }], b: { name: "b", c: [1, 3, 5] } }, { depth: Math.Infinity });
console.log("_inspect", _inspect);
2.4 url模块
2.4.1 url.parse(url:string,opt:boolean)
描述:解析 URL 字符串,返回一个解析后的对象。
const _url = "https://juejin.cn/book/7304230207953567755/section/7304642570489954358?utm_source=course_list"
console.log("~~", url.parse(_url));
console.log("~~", url.parse(_url, true));
2.4.2 url.URL
描述:和全局的 URL 一样,创建一个 URL 实例,提供许多开箱即用的操作。
const testUrl = 'https://www.baidu.com?search=juejin'
console.log('url.URL === URL', url.URL === URL) // true
console.log(new URL(testUrl))
2.5 readline模块
//创建一个实例
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
})
// 询问
rl.question('What is your name? ', (name) => {
console.log(`Hello, ${name}!`)
// rl.close()
})
rl.write('Hello, World!\n') //Hello, World!!
rl.setPrompt('node> ') // 设置提示符
rl.prompt() // 显示提示符
rl.on('line', (line) => {
// 监听行事件
switch (
line.trim() // 去除收尾空白字符,进行简单的命令选择判断
) {
case 'hello':
console.log('world') // 输出 'world'
break
case 'exit':
rl.close() // 关闭 readline 接口
break
default:
console.log(`Say what? I might have heard '${line.trim()}'`) // 输出收到的指令
break
}
rl.prompt() // 显示提示符
})
2.6 timer 定时器
setTimeout(callback, delay[, ...args]): 在 delay 毫秒之后执行一次 callback
setInterval(callback, delay[, ...args]): 每隔 delay 毫秒执行一次 callback
setImmediate(callback[, ...args]): setImmediate 的执行时机是:在当前执行栈中的所有同步代码以及任何 I/O 回调之后,但是在任何新的定时器(如 setTimeout 和 setInterval)回调之前。然而,如果与 process.nextTick() 相比,process.nextTick() 总是会在 setImmediate 之前执行,前提是它们都在同一个事件循环迭代中被调用。
process.nextTick(callback[, ...args]): 在Node.js中,process.nextTick() 函数被用于将回调函数放置在事件循环的当前执行栈的尾部,即在当前执行栈中的所有同步代码执行完毕,在当前执行栈清空后,但在任何I/O回调(包括定时器回调如setTimeout和setInterval)之前执行
setImmediate(() => console.log('setImmediate'))//
setTimeout(() => console.log('setTimeout'), 0)//
process.nextTick(() => console.log('nextTick'))//最先执行
setInterval(() => console.log('setInterval'), 1000)//
输出顺序:nextTick
setImmediate
setTimeout
setInterval