(啊我真棒,学完了这节)
nodejs是运行在服务端的js.
把我们平时用到的js文件放在node上执行,它就是nodejs.
在终端执行js文件:
node 文件名.js
vscode终端快捷键:ctrl+`
一.安装
在node官网,一般选稳定版:
检查是否安装成功:
node -v
或者用homebrew安装(mac).
如果在windows下显示node不是内部命令, 则需要配置环境变量:
windows配置环境变量: 计算机--属性--高级系统设置--环境变量, 在系统变量里找到path,加上我们要添加的新路径(和之前的用分号隔开),然年确定. 之后关了终端重新打开一下,输入命令就可以用了.
二.搭建node服务器
新建文件http.js:
const http = require("http")
const server = http.createServer((req, res) => {
res.write("hello world")
res.end()
})
server.listen(3000) // 3000是端口号
然后在终端执行(node启动成功之后没任何提示,没报错就是成功了哈哈哈):
node http.js
访问服务:
本机访问:方法一. http://localhost:3000/
方法二. 127.0.0.1:3000
方法三. ip:3000(ip是自己电脑的ip,在终端输入ipconfig就能看到)
同一局域网下的其他电脑访问:ip:3000
每次改动之后都要重启服务之后客户端才能刷新, 所以我们安装nodemon,可以实现热更新:
npm i nodemon -g
安装成功之后用nodemon启动服务:
nodemon http.js
创建服务的就是服务端,启动服务的就是客户端.
三.node中的模块化
我们平时写js的时候,变量命名重复等会引起变量污染.在nodejs里,用commonjs规范,把代码划分成不同的模块,每个模块有自己独立的命名空间,相互之间不会产生影响,代码也变得清晰可读和易于维护.通过模块之间的相互引用.
客户端的模块化工具主要有:AMD(sea.js), CMD(require.js),
服务端的模块化工具commonjs是node自带的.
模块之间引用: 导出module.exports,引入require('xxx')
导出(/home/index.js):
let a = 10
class Person{
constructer() {
this.name = "张三"
}
hobby() {
console.log("喜欢篮球")
}
}
module.exports = { // 可以导出变量和构造函数
a,
Person
}
// 也可以用exports导出:
// exports.a = a
// exports.Person = Person
// exports是module.exports的引用 module.exports= exports
引入(inex.js):
let home = require('./home') // 相当于require('./home/index.js')
console.log(home.a) // 10
let zhngsan = new home.Person
zhngsan.hobby() // 喜欢篮球
四.node中的node-modules
从外部引入的node模块,一般都会放在文件夹node_modules里,
从node_modules引入模块的时候,不用加./(引入文件和文件夹的时候需要):
index.js:
// require("nodetest")
let {a, b} = require("nodetest")
console.log(a)
/node_modules/nodetest/main.js:
console.log("main.js")
module.exports = {
a: 10,
b: "bbb"
}
package.json是描述功能性文件.
五.npm包管理器
以上,是引入模块的三种方法:
1.引入文件:require('./a.js')
2.引入文件夹:require('./home') // 默认引入./home/index.js,在该文件里引入文件夹下所有文件,则可通过 require('./home')引入整个文件夹
3.引入node_modules下的模块:require("nodetest") //注意前面没有./
引入第三方模块也是放在node_modules下面,直接引入,不用加./, 引入内置模块(如http)的时候,不用放在node_modules文件夹下,直接通过require("http")引入.
npm:包管理器,用来安装第三方模块,也可以上传自己的包https://www.npmjs.com/
六.npm常用指令:
npm install xxx// 安装模块
npm init // 初始化项目,新建package.json文件(一直回车就可以)
npm i // 是i是install的简写,用法同上
npm uninstall xxx// 删除模块
npm i xxx --save // 安装模块并将版本信息加在package.json文件的dependencies(运行依赖)里,这样别人拿到项目只用npm i就能安装所有依赖
npm i xxx -S // -S是--save的简写,用法同上
npm i xxx --save-dev // 版本信息会加在package.json文件的devDependencies(开发依赖)里
(开发依赖是只有开发时需要,上线运行的时候不用,比如sass,less等. 运行依赖是都需要,比如query,vue,react等.)
npm i xxx -D // -D是--save-dev的简写,用法同上
npm update xxx // 更新
npm i [email protected] // 安装指定版本的依赖
依赖会安装在当前项目下的node_modules文件夹里,如果当前目录没有node_modules,会往上一层目录查找,直到电脑的根目录(npm root -g命令可以看到是哪个).只要往上某一层node_modules里有需要的依赖,都可以使用
npm root // 查看当前项目下的node_modules路径
npm root -g // 查看根目录下的node_modules路径
npm i xxx -g // 全局安装,会被装在root目录下,这样子所有项目都可以使用(不加-g只会装在当前项目里)
七.fs文件操作
fs模块也是内置模块,用来操作文件
1.文件操作
(1).文件写入:fs.writeFile()
const fs = require("fs")
// 1.文件写入
fs.writeFile('1.txt', '我是写入的内容11111', {flag: "w"}, function(err) { // 第三项可以不写 不写默认{flag: "w"}
// flag: a追加写入 w写入 r读取
// err是错误信息
if(err) {
return console.log(err)
}
console.log("写入成功")
})
(2).文件读取:fs.readFile()
// 文件读取
fs.readFile('1.txt', 'utf8', (err,data) => { // 如果不加utf8,读取到的会是Buffer格式,即node里的二进制
if(err) {
return console.log(err)
}
console.log(data)
// console.log(data.toString()) // 如果是Buffer格式,加上.toString()就可以转成字符串格式
})
#不管是文件写入还是文件读取,都是异步的,如果要改成同步格式,则在后面加上Sync(目录操作也是): fs.writeFileSync(),fs.readFileSync()
// 同步写法
let data = fs.readFileSync("1.txt")
console.log(data.toString())
(3).修改文件名:fs.rename()
fs.rename('1.txt', '2.txt', err => {
if(err) {
return console.log(err)
}
console.log("修改成功")
})
(4).文件删除:fs.unlink()
fs.unlink('2.txt', err => {
if(err) {
return console.log(err)
}
console.log("删除成功")
})
(5)文件复制:fs.copyFile()
fs.copyFile('index.js', 'myindex.js', err => {
if(err) {
return console.log(err)
}
console.log("复制成功")
})
2.目录操作
(1).创建目录:fs.mkdir()
fs.mkdir("11", err => {
if(err) {
return console.log(err)
}
console.log("创建成功")
})
(2).修改目录名称:f.rename()
fs.rename("11", "22", err => {
if(err) {
return console.log(err)
}
console.log("修改成功")
})
(3).读取目录内容:fs.readdir()
fs.readdir("22", (err, data) => {
if(err) {
return console.log(err)
}
console.log(data) // [ '1.html', '2.txt' ]
})
(4).删除目录(空文件夹/目录): fs.rmdir()
fs.rmdir('home', err => {
if(err) {
return console.log(err)
}
console.log("删除成功")
})
(5).删除非空目录:
!!!!!通过nodejs删除的文件不会经过回收站,谨慎删除!
// 思路: 先把文件夹里文件删除,再删除空文件夹
function removeDir(path) {
let data = fs.readdirSync(path) // 读取文件夹下的内容(返回一个数组)
data.forEach(item => {
let url = path + '/' + item // 当前路径
let sta= fs.statSync(url) // 当前目录/文件的详细信息
if(sta.isFile()) { // 当前路径是文件
fs.unlinkSync(url) // 删除
} else { // 当前路径是文件夹
removeDir(url) // 继续查找
}
})
// 最后删除剩下的空文件夹
fs.rmdirSync(path)
}
removeDir('22')
3.文件和目录通用的方法
(1).判断文件/目录是否存在:fs.exists() 返回true/false
fs.exists("22", res => {
console.log(res) // true
})
(2).获取文件/目录的详细信息: fs.stat()
判断是否为文件:data.isFile()
判断是否为文件夹:data.isDirectory()
两个都是返回true/false
fs.stat('index.js', (err, data) => {
if(err) {
return console.log(err)
}
// console.log(data) // 返回一些详细信息
// 判断是否为文件:
// let res = data.isFile()
// 判断是否为文件夹:
let res = data.isDirectory()
console.log(res)
})
八. buffer
buffer在nodejs里是一个类,可以当成一种数据格式, 在数据传递过程中以二进制的方式传输.
1.创建
// 方法一: new Buffer() // 6.0之前
// 方法二: Buffer.alloc()
let buffer = Buffer.alloc(10); //10字节
console.log(buffer) //
// 方法三: Buffer.from()
let buffer = Buffer.from("大家好")
console.log(buffer) //
2.buffer转成字符串
xxx.toString()
let buffer = Buffer.from([0xe5, 0xa4, 0xa7, 0xe5, 0xae, 0xb6, 0xe5, 0xa5, 0xbd])
console.log(buffer) //
console.log(buffer.toString()) // 大家好
3.解决乱码
// 方法一: 连接 解决乱码问题
let buffer1 = Buffer.from([0xe5, 0xa4, 0xa7, 0xe5])
let buffer2 = Buffer.from([0xae, 0xb6, 0xe5, 0xa5, 0xbd])
console.log(buffer1.toString(), buffer2.toString()) // 会乱码
let buffer3 = Buffer.concat([buffer1, buffer2])
console.log(buffer3.toString()) // 大家好
// 方法二: 用node内置模块string_decoder
let {StringDecoder} = require("string_decoder")
let decoder = new StringDecoder()
let buffer1 = Buffer.from([0xe5, 0xa4, 0xa7, 0xe5])
let buffer2 = Buffer.from([0xae, 0xb6, 0xe5, 0xa5, 0xbd])
let res1 = decoder.write(buffer1)
let res2 = decoder.write(buffer2)
console.log(res1) // 大
console.log(res2) // 家好
九.stream流
对于很大的文件,直接读取可能会导致内存溢出等问题,所以可以用stream流的形式,把它切割成很多个很小的块,像水流一样读取和传递.
流会把数据分成64kb的小文件里传输.
// 读取文件
const fs = require("fs")
// 原本的写法
// let res = fs.readFileSync("1.txt")
// console.log(res)
// 用stream流的方式
let res = fs.createReadStream("1.txt")
let str = ""
res.on("data", chunk => { // 读取过程中被分成好多个64kb的小块(这里相当于循环)
str += chunk
// console.log(chunk.toString()) // 读取到的每个小块
})
res.on("end", () => { // 流读取完成
console.log(str) // 最终结果(所有小块的总和)
})
// 写入流
let ws = fs.createWriteSteam("2.txt");
res.pipe(ws) // 通过管道将内容一小块一小块写入到2.txt里