Node.js
事件循环机制
setImmediate()是将事件插入到事件队列尾部,主线程和事件队列的函数执行完成之后立即执行setImmediate指定的回调函数,和setTimeout(fn,0)的效果差不多
process.nextTick()方法可以在当前"执行栈"的尾部-->下一次Event Loop(主线程读取"任务队列")之前-->触发process指定的回调函数。也就是说,它指定的任务总是发生在所有异步任务之前,当前主线程的末尾。
事件触发器模块Events
const EventEmitter = requier("events").EventEmitter;
const emitter = new EventEmitter;
-
emitter.on('eventName', callback) 绑定事件
当事件名为“newListener”时表示监听后续是否添加了新的监听事件,每添加一个新的监听事件都会触发一次并执行回调
-
emitter.off('eventName', callback) 解绑事件
-
emitter.emit('eventName') 触发对应的事件,执行绑定在该事件上的回调函数
-
emitter.once('eventName', callback) 绑定后只触发一次,触发完毕后解绑
-
emitter.setMaxListeners(number) 设置同一事件名能设置的监听事件最大数,默认为10,超出只会警告而不报错
-
emitter.getMaxListeners() 返回 EventEmitter 当前的监听器最大限制数的值
-
emitter.listeners("eventName") 返回名为 eventName 的事件的监听器数组的副本
URL模块
- URL的解析
const URL = require("url").URL;
const myUrl = new URL("https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=nodejs&oq=nodejs&rsv_pq=d7fa015100007271&rsv_t=aa05WH%2FPArCuBuKN337J%2BU6sVgj9%2BXf95e%2F8rq7tN8CgOI2AwwkmOSAGEvs&rqlang=cn&rsv_enter=1&inputT=366&rsv_sug3=12&rsv_sug1=10&rsv_sug7=100&rsv_sug2=0&rsv_sug4=1165&rsv_sug=1");
//返回一个关于这个url相关的信息的实例对象
myUrl.searchParams 返回一个关于这个url相关信息的map结构,需要使用.get()方法取得属性值,没有值的属性为空字符串
- URL的拼接
const resolve = require("url").resolve; // url拼接
resolve("user/wula", "51-url-fs"); // user/51-url-fs 处在user的同目录下
resolve("user/wula/", "51-url-fs"); // user/wula/51-url-fs
resolve("user/wula/", "/51-url-fs"); // 51-url-fs /表示处在根目录下
- URL的序列化与反序列化
const URL = require("url").URL;
const qs = require("querystring");
const myUrl = new URL("https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_id...");
qs.parse(myUrl.search.slice(1)); //序列化,返回一个对象,里面的键值对为url中的搜索条件
qs.stringify({wula:123, simple:456}); //反序列化, wula=123&simple=456
加密模块crypto
const crypto = require("crypto");
console.log(crypto.getHashes()); //查看hash加密方式有哪些
let pwd = "simple";
const obj = crypto.createHash("sha256");
obj.update(pwd); //通过加密对象对数据进行加密
console.log(obj.digest()); //得到加密数据,得到一个buffer对象(默认为二进制)
console.log(obj.digest("hex")); //得到加密数据,以16进制形式表示
文件操控模块fs
const fs = requier('fs');
- 文件的读取
fs.readFile("./simple.txt", "utf8", (err, data) => { //路径,字符集 ,回调函数(读取发生错误时候的错误信息, 读取成功得到的数据)
console.log(err); //err为null表示读取成功,读取失败为对象,里面存储错误信息
console.log(data); //默认以二进制保存的buffer对象,有设置字符集以字符集形式展示
});
fs.readFileSync("./simple.txt", "utf8"); //同步方法,返回值为读取得到的数据
- 文件的写入
let data = "simple";
fs.writeFile("./test.txt", data, (err) => {
if (err) throw err;
});
fs.writeFileSync("./test.txt", data);
fs.appendFile(“./test.txt”, “添加的内容”, “utf-8”, err => {}); //非覆盖的添加内容
- 创建文件夹
fs.mkdir("./01", err => {
//只能创建一个未知的文件夹,且不能创建多个文件夹
});
- 读取文件夹目录
fs.readdir("../51", (err, data) => {
if(err) throw err;
console.log(data); //data为一个数组,保存的是该目录下所有文件的文件名
});
- 判断是否为文件
const stat = fs.statSync("../51");
console.log(stat.isDirectory()); //true为文件夹, false为其他文件
console.log(stat.isFile()); //false为文件夹, true为其他文件
- 监听文件
fs.watchFile("./wula.txt", (a, b) => { //监听路径中的文件内容是否进行修改,会在文件内容修改后触发回调函数
console.log(a); //a为文件修改前的状态对象
console.log(b); //b为文件修改后的状态对象
});
流模块steam
- 流模块
const fs = require("fs"); //fs模块继承了stream
const read = fs.createReadStream("./simple.txt"); //创建一个读取流,返回一个对象,为暂停状态
// 流有两个状态: 暂停状态 释放状态
read.resume(); //改变流的状态为释放状态,只有为释放状态的时候流才会流动
read.setEncoding("utf-8"); //设置输出数据的字符集
read.on("data", data => {
//随着流的不断流动会多次触发回调
}); //绑定data事件后可以让流变为释放状态,还会监听流的流动以得到数据(默认为二进制buffer对象)
read.on("end", () => {
}); //监听流的流动,流动结束后触发回调函数
- 管道服务
const fs =require("fs");
const read = fs.createReadStream("./simple.txt");
const write = fs.createWriteStream("./wula.txt");
read.pipe(write); //让数据流从读取流流向写入流
write.write(“”); //往写入流中写入数据,覆盖的
- 可读流
const Readable = require("stream").Readable;
const read = new Readable(); //创建一个可读流对象
read.setEncoding("utf-8");
read.push("1");
read.push("2");
read.push("3");
read.push(null); //在最后push一个null表示数据放完了,不然会报错
HTTP模块
在node中HTTP服务继承自TCP服务器,它能够与多个客户端保持连接,由于其采用事件驱动的形式,并不为每一个连接创建额外的线程或进程,保持很低的内存占用,所以能实现高并发。下面是一个实例。
const http = require("http");
const fs = require('fs');
//创建一个服务
const server = http.createServer((req, res) => {
// req 请求体对象 res:响应体对象
//请求体的属性:req.url req.method req.httpVersion req.headers
//req.headers 返回键值对形式的请求头,以供业务逻辑调用
//根据请求方法来进行处理
if (req.method === "GET") {
res.writeHead(200, {
"Content-Type": "text/html;charset=utf-8"
});
//根据请求路径进行页面渲染
switch (req.url) {
case "/wula":
res.write(fs.readFileSync("./01.html", "utf8"));
break;
default:
res.write(fs.readFileSync("./default.html", "utf8"));
break;
}
}
//设置响应头
//设置允许跨域,CROS跨域
res.setHeader("access-control-allow-origin", "*");
//setHeader可多次调用设置,但只有调用writeHead后,报头才会写入到连接中
res.writeHead(200, {
"Content-Type" : "text/html;charset=utf-8"
});
//text/plain :纯文本 text/html:标签
//写入响应主体
//res.write可多次调用,res.end调用会先调用write发送数据,然后发送信号告知服务器响应结束
res.end("<div>结束会话</div>");
});
//监听端口号
// server.listen(3000, "127.0.0.1");
server.listen(3000);
console.log("开始监听3000端口");
http客户端
在node中通过http.request(options,connect)这个API来构造HTTP客户端
比如说要构建一个代理服务器(3003端口),当我向它发起请求的时候它会返回3000端口的响应,这个时候就需要在服务器上创建一个向3000端口的请求。
const http = require("http"),
request = http.request; //得到请求的api
let options = {
host : "localhost", //服务器域名或IP地址
port : 3000,
method : "GET"
/*
hostname 服务器名字
path 路径
headers 请求头
...
*/
};
//调用请求方法,返回一个请求对象
let reqObj = request(options, res => {
let dataObj = null;
res.setEncoding("utf8"); //设置响应主体流的编码方式
res.on("data", data => {
dataObj = data;
// console.log(data); //接收到的数据
});
//监听res的end事件
res.on("end", () => {
//创建一个服务,等待客户端的请求过来
http.createServer((req, res) => {
res.setHeader("Access-Control-Allow-Origin", "*");
res.write(JSON.stringify(dataObj));
res.end();
}).listen(3003, () => {
console.log("服务正在监听3003端口");
});
})
});
//如果请求失败,调用err事件
reqObj.on("error", err => {
console.log(err);
});
//写入请求主体
reqObj.write("");
reqObj.end();
这样设置后就允许所有向3003端口的请求都会返回3000端口的响应了。