文章目录
前言
nodejs主要是做web服务端
nodejs内置了很多的包,需要不同的功能可以引入对应的包
一、创建简单的服务器
// 1. 创建一个简单的web服务器,引入网络模块
const http = require("http");
// 2. createServer创建一个web服务器,并传入回调函数
http.createServer(function (request, response) {
// request是请求对象,客户端发送请求携带的信息放入该对象
// response 是服务端的响应对象,服务器相关的操作都是在该对象
// writeHead 设置服务端响应头,200是status状态码,content-type是服务端返回的数据类型是文本类型,charset=UTF-8解决输出中文乱码
response.writeHead(200, { "content-type": "text/plain";charset=UTF-8' });
// end方法向客户端发送数据
response.end("hello node.js");
}).listen(8080);
console.log("server start ok");
二、文件模块
1. fs 模块
文件操作有同步和异步版本,推荐用异步版本
1.读文件 readFile
同步模式中,先去读文件,读完后才会执行后面的代码。
异步模式中,先执行fs.readFile()函数立刻执行后面的代码,fs.readFile()函数会去读里面的文件,成功后执行。
// 引入fs文件模块,fs模块可以操作系统中的各种文件
const fs = require("fs")
// 1. 同步模式(阻塞模式),前面的代码执行完成后才能执行后面的代码
// 同步方式读取hello02.text文件内容
const txt = fs.readFileSync("hello.txt")
// 读取内容以流方式展示,需要转为字符串
console.log(txt.toString());
console.log("文件读取中");
// 结果:Hello text! 文件读取中
//2. 异步方式(非阻塞模式),前面代码不影响后面代码执行,同时执行
fs.readFile("hello.txt",(err,data)=>{
if(!err){
console.log(data.toString());
}
})
console.log("文件读取中");
// 结果:文件读取中 Hello text!
2. 查看文件信息 stat
stat(path,callback(err,status))
const fs = require("fs");
fs.stat(__dirname + "/assets/a1.txt", function (err, status) {
if (!err) {
console.log(status);
}
});
3. 原始打开读取关闭文件
open(path,flag[,mode],callback(err,fd))
path文件路径
flag打开文件的模式
mode文件权限(默认是0666[可读可写])
const fs = require("fs")
fs.open("txt1.txt","r",(err,fd)=>{
if(err){
console.log(err.message);
} else{
// 打开文件返回的fd并不是文件内容,只是文件打开的一个状态
// console.log(fd); // 3
// 打开文件以后需要用read方法,读取文件内容并存入缓存区
// read(fd,buffer,offset,length,position,callback(err,bytes))
let buf = new Buffer.alloc(1024)
fs.read(fd,buf,0,buf.length,0,(err,length)=>{
if(err){
console.log(err.message);
} else {
console.log("读取了:"+ length +"读取内容:"+ buf.toString());
}
// 读取完文件后需要关闭文件,释放内存
fs.close(fd,(err)=>{
if(err){
console.log(err.message);
return
}
console.log("文件已关闭");
})
})
}
})
4. node封装 打开读取关闭文件
读取文件 readFile
readFilereadFile(path,callback(err,data))
读取文件操作的方法,内部封装了打开,读取,关闭的操作。
const fs = require("fs")
fs.readFile("text.txt",(err,data)=>{
if(err){
console.log(err.message);
return
}
console.log(data.toString());
})
写入文件 writeFile
写入文件的方法,没有文件则创建文件,有则覆盖
const fs = require("fs")
fs.writeFile("txt1.txt","覆盖的文本txt",(err)=>{
if(err){
console.log(err.message);
}
console.log("写入成功");
})
删除文件 unlink
const fs = require("fs")
fs.unlink("txt1.txt",(err)=>{
if(err){
console.log(err.message);
}
console.log("删除成功");
})
5. 目录的创建读取删除
创建目录 mkdir
const fs = require("fs")
fs.mkdir("static",(err)=>{
if (err) {
console.log(err.message);
return;
}
console.log("创建成功");
})
删除目录 rmdir
const fs = require("fs")
fs.rmdir("static",(err)=>{
if (err) {
console.log(err.message);
return;
}
console.log("创建成功");
})
读取目录 readdir
读取目录下的所有文件,需要使用递归方式,判断目录下面如果还有目录,接着往下读。
isDirectory()
判断是否是一个目录
const fs = require("fs")
fs.readdir("assets",(err,files)=>{
if (err) {
console.log(err.message);
return;
}
// 返回的是文件对象数组
console.log(files);
})
// 读取目录下的所有文件
function readAllDir(path){
// 传入path路径,判断是一个文件还是目录
fs.stat(path,(err,status)=>{
if (err) {
console.log(err.message);
return;
}
// 判断如果是一个目录,则直接读取目录
if(status.isDirectory()){
fs.readdir(path,(err,files)=>{
if (err) {
console.log(err.message);
return;
}
files.forEach((item)=>{
readAllDir(path + "/" + item)
})
})
} else { // 是文件
console.log("文件名:" + path);
}
})
}
readAllDir("assets")
2. events 事件循环系统监听
nodejs 是单进程单线程,但是v8引擎提供了异步执行的回调接口,所以nodejs可以同时处理大量的并发请求,性能非常高
nodejs 所有事件的机制都是使用的观察者模式(事件驱动程序)。
在事件驱动程序中,会有一个事件循环系统监听事件,当检测到事件执行,触发对应的回调函数。
// 引入events 模块(nodejs的事件都是基于events模块封装的)
const events = require("events");
// 1. 创建事件触发器(eventEmitter)对象
let eventEmiter = new events.EventEmitter();
// 2. 创建消费者(监听者),监听事件的执行,并触发对应的回调函数
// 监听connect事件,如果触发connect事件,则执行对应的回调函数
// on监听的事件则会进入事件循环系统,监听connect事件
eventEmiter.on("connect", function (data) {
console.log("事件执行", data);
});
//3. 触发connect事件,并向回调函数传递参数
setTimeout(function () {
eventEmiter.emit("connect", { name: "zhang" });
}, 2000);
3. buffer 缓冲区
Buffer类可以创建一个存放二进制数据的缓存区,可以存储比较原始的数据类型
// 1. Buffer.from(string, encode) 返回一个string初始值的buffer实例
// string是buffer的存储数据,encode是存储数据编码格式(默认是utf-8,可以省略)
let buff = Buffer.from("hello 中国");
// 默认buff显示用16进制,需要用toString转为字符串。
console.log(buff.toString());
// 2. alloc(size[,fill[,encode])
// 返回一个指定大小(存储字节数量固定)的buffer实例,size是字节数,fill是存储的内容,encode编码方式
// 超过的字节不会存储成功
let buf1 = Buffer.alloc(6, "xxxxxxxx");
// 3. write(string,[offset,[length,encode]])
// 向buffer缓存区重新填写内容,超过的长度会被丢弃
// string写入的内容,offset是开始的位置索引(默认从0),length是写入的长度(默认是buffer的长度)
let len = buf1.write("chinese", 3, 2);
console.log(buf1.toString());
// 4. 合并缓存区
const bufa = Buffer.from("html");
const bufb = Buffer.from("javascript");
const bufc = Buffer.concat([bufa, bufb]); // concat合并多个buffer并返回一个新的
console.log(bufc.toString());
4. stream 流
是数据的传输,是有序的,有方向的数据传输(对buffer的一种封装)
stream 流对象是EventEmitter对象的一个实例,stream一般是用于大量数据的传输
strea流是fs模块里面的api
有四种流:
- 可读流
Readable
- 可写流
Writable
- 可读写流
Duplex
Transform
可读写过程中还可以修改数据
1. 可读流 createReadStream
const fs = require("fs");
// 1. 创建可读流读取文件
let readStream = fs.createReadStream("hello02.text");
// 1.2 设置流的编码格式,默认utf-8,可省略
// readStream.setEncoding("utf-8")
// 1.3 监听流读取数据,读取数据会触发data事件,如果数据量比较大,读取事件较长会多次触发data
let data = "";
readStream.on("data", function (chunk) {
data += chunk;
});
// 1.4 流读取数据完成触发end事件
readStream.on("end", function () {
console.log("数据读取完成", data);
});
// 1.5 流读取数据出错触发error事件
readStream.on("error", function (err) {
console.log(err.message);
});
2. 写入流 createWriteStream
const fs = require("fs");
const str = "china very good";
let writeStream = fs.createWriteStream("test03.txt");
writeStream.write(str); // 把str内容写入到test03.txt文件
writeStream.on("finish", function () {
// 写入完成触发的函数
console.log("write ok");
});
writeStream.on("error", function (err) {
console.log(err.message);
});
3. 管道流 pipe
把一个数据流通过流 流向另外一个流,如文件复制
const fs = require("fs")
let readStream = fs.createReadStream("text.txt")
let writeStream = fs.createWriteStream("txt1.txt")
// 读取流内容直接流到写如流
readStream.pipe(writeStream)
4. 链式流
多个流可以链接操作,如多个管道流链接使用
const fs = require("fs")
const zlib = require("zlib")
//如压缩文件:
fs.createReadStream("txt1.txt")
.pipe(zlib.createGzip())
.pipe(fs.createWriteStream("txt2.txt.gz"))
// 解压文件
fs.createReadStream("txt2.txt.gz")
.pipe(zlib.createGunzip())
.pipe(fs.createWriteStream("txt3.txt"))
5. 模块作用域
commjs规范
nodejs的模块使用的commjs
规范,模块的作用域是在模块内部。
模块第一次加载会被放入缓存
模块加载顺序: 1. 先从缓存 2. node.js 内置模块 3. 本地模块(node_modules或者自定义)
// 引入自定义模块
let user = require("./module/user")
const peo = require("./module/person")
两种写法:
// 默认导出的是一个对象,给导出对象添加属性
exports.name = "anna",
exports.age = 29,
exports.say = ()=>{
console.log("say~~");
}
// 修改导出数据类型,可以导出一个对象或函数
module.exports = {
name:"zhang",
age:19,
};
es6模块(安装工具)
nodejs不支持es6模块
如果需要支持import语法
,需要安装babel
编译工具
cnpm i babel-core babel-preset-env -S
- 在当前项目目录创建
.babelrc
的配置文件
{
"presets": ["env"]
}
- 全局安装
cnpm i -g babel-cli
- 使用
babel-node xxx.js
执行js文件
import esUser from "./modules/es6user";
三、
- nodejs只保留的基础的js功能,没有DOM,BOM对象。因为node.js没有浏览器环境。
- node.js 没有window对象,nodejs的全局变量是global,nodejs的全局变量都是global对象的属性
1. 全局变量 global
//1 隐式定义(不声明变量,直接赋值)
test = "a1";
console.log(test, global.test);
//2 直接把变量作为属性添加到global对象上
global.test2 = "test2";
console.log(global.test2);
2、nodejs提供的常用全局变量
// 1. __filename 输出当前执行文件的绝对路径
console.log(__filename);
// 2. __dirname 输出当前执行文件目录的绝对路径
console.log(__dirname);
// 3. 保留了定时器的函数(setTimeout,clearTimeout,setInterval,clearInterval)
// 4. process 用于描述当前node进程状态,也是提供了一个与操作系统交互的接口(了解)
process.stdout.write("hello process"); // 打印在终端上
2. 工具函数 util模块
const util = require("util");
// 1. 判断各类数据类型的函数
let arr = [];
console.log(util.isArray(arr));
// 2. callbackify 将async异步函数或者返回值为promise对象的函数转为回调函数风格
async function f1() {
return "hello async";
}
const f1back = util.callbackify(f1);
f1back(function (err, data) {
if (!err) {
console.log(data);
}
});
//3. inspect(object[,bool,[deep,[colors]]]) 将一个对象转为字符串
// object 对象
// bool 显示对象的隐藏信息,默认是false
// deep 显示对象的层数,默认只显示2层,null则是全显示
// colors 属性值的颜色
let users = {
name: "zhang",
age: 12,
address: {
city: "chengdu",
family: [
{
name: "li",
age: 42,
frend: {
name: "wang",
age: 12,
},
},
],
},
};
console.log(util.inspect(users, true, null));