1 buffer
- 不需要require 的全局变量
- 让node 使用二进制数据操作
- 不占用v8的内存,可以使用node管理
- 一般steam流使用,充当缓存区域---文件读写
alloc
创建指定大小的buffer
let buffer = Buffer.alloc(10) // 10 字节
let unsafeUn = Buffer.allocUnsafe(10) // 在垃圾回收后获取了没有清理干净的垃圾锁片
console.log(buffer)
console.log(unsafeUn)
let b1 = Buffer.from("1") // chatCodeAt() 49 form(s1,s2) s2=utf-8 31=2*16 1 + 1*16 0
console.log(b1)
let b2 = Buffer.from([1,2,"abc"]) // abc 无法触发
let b3 = Buffer.from([1,2,Buffer.from("abc")]) //
let b4 = Buffer.from("中").toString()
console.log(b2)
console.log(b3)
console.log(b4)
allocUnsafe
创建指定大小的buffer(不安全)
from
接收数据创建buffer
buffer的静态方法
// fill
let bf = Buffer.alloc(6)
bf.fill("123")
console.log(bf) // 结果 <Buffer 31 32 33 31 32 33> 默认填满
let bf1 = Buffer.alloc(6)
bf1.fill("123",1,4) //<Buffer 31 32 33 31 32 33> 从第一位开始到第4位置结束
console.log(bf1)
// write
let bf = Buffer.alloc(6)
bf.write("123")
console.log(bf) // 结果 <Buffer 31 32 33 00 00 00> 不会默认填满
let bf2 = Buffer.alloc(6)
bf2.write("123",1,3) // <Buffer 00 31 32 33 00 00> 从第一位开始到第3位置结束
console.log(bf2)
// toString 转换ask吗到字符
console.log(bf2.toString())
write 和fill的区别是,fill主动填满内存,write不会
slice像数组slice 实例
let bf = Buffer.from("DDD")
console.log(bf.slice(2,3).toString())
copy 实例方法
let bf1 = Buffer.alloc(6)
let bf2 = Buffer.from("拉钩")
bf2.copy(bf1,3,3,6) // 第一个3 值得是b2往左的偏移量,第2个是copy的起始位,6是结束位置
console.log(bf1.toString())
console.log(bf2.toString())
concat 静态方法
let a = Buffer.from("111")
let b = Buffer.from("222")
console.log(Buffer.concat([a,b],5).toString()) // concat 将两个buffer 合并, 5是限制长度
isBuffer 静态方法
let a = Buffer.from("111")
console.log(Buffer.isBuffer(a))
module.export 和 export 的不同
module.export 和 export的地址是执行一个地方
let name1 = "jack"
let getName = () => {
return name1
}
// module.exports = {
// name1,
// getName
// }
// 上面等于 exports.name1= name1
// exports.getName= getName
// 但是不能把 exports={name:111},因为
exports.name1 = name1
exports.getName = getName
console.log(module, "modulePage")
module 对象数据
Module {
id: '/Users/liukun/Desktop/node/common/module.js', // 当前文件夹
path: '/Users/liukun/Desktop/node/common', // 调用的位置
exports: { name1: 'jack', getName: [Function: getName] }, // 导出
parent: Module { // 父级
id: '.',
path: '/Users/liukun/Desktop/node/common',
exports: {},
parent: null,
filename: '/Users/liukun/Desktop/node/common/index.js',
loaded: false,
children: [
[Circular]
],
paths: [
'/Users/liukun/Desktop/node/common/node_modules',
'/Users/liukun/Desktop/node/node_modules',
'/Users/liukun/Desktop/node_modules',
'/Users/liukun/node_modules',
'/Users/node_modules',
'/node_modules'
]
},
filename: '/Users/liukun/Desktop/node/common/module.js', // 文件名称
loaded: false,
children: [], // require 的依赖
paths: [ // node查找位置 以 .js .json .node 补足查找
'/Users/liukun/Desktop/node/common/node_modules',
'/Users/liukun/Desktop/node/node_modules',
'/Users/liukun/Desktop/node_modules',
'/Users/liukun/node_modules',
'/Users/node_modules',
'/node_modules'
]
}
require
- 查询文件系统(有可能查缓存)node查找位置 以 .js .json .node 补足查找
- 加载所有文件js(字符串)---readfileSync
- 执行所有文件(字符串转为js),然后包装module.export 挂载内容
如何执行 字符串js
- eval
let str = "console.log(1)"
eval(str)
- new Function
let num = 1
new Function("num","console.log(num+1)")(num)
- node的vm模块
let fs = require("fs")
let vm = require("vm")
let content = fs.readFileSync("./rs.txt")
vm.runInThisContext(content)
node 事件队列
- timer 执行settimeout
- pendding callbacks 执行系统操作的回调例如 tcp udp
- ide,prapare 只在系统内部使用
- poll 执行i/o相关 例如 文件读写
- check 执行setImmediate中的回调
- close callbacks 执行close相关事件
const { setImmediate } = require("timers")
setImmediate(() => {
console.log("setInmmet")
})
setTimeout(() => {
console.log("setTIme")
})
Promise.resolve().then(() => {
console.log("promise")
})
console.log("start")
process.nextTick(() => {
console.log("nextTick")
})
console.log("end")
// start
// end
// nextTick
// promise
// setTIme
// setInmmet
注意nextTIck 大于promise
node事件循环和浏览器的区别
- node有6个事件
- 浏览器只有宏伟任务
node事件循环的问题
setImmediate(() => {
console.log("setImmediate")
})
setTimeout(() => {
console.log("setTimeout")
})
会发现有时答案相反:原因setTimeout 后面的时间定时器的值不写为0的时候照成的,有时候会对时间计算错误
问题
const fs = require("fs")
fs.readFile("./a.txt", () => {
setImmediate(() => {
console.log("setImmediate")
})
setTimeout(() => {
console.log("setTimeout")
})
})
// setImmediate setTimeout
应为在 执行poll 的io队列后会去执行 chek 队列的setImmediate 。按照队列顺序往下走
stream 流
- readable 可读流,能够实现数据的读取
- writeable 可写流,能够实现数据的写入
- duplex 双工流,可以实现数据的读写
- transform 转换流。可以实现数据的读写,并且可以进行转换
并且 stream 模块 实现了4个具体抽象
所有的stream 都继承了EventEmitter
const fs = require("fs")
let rs = fs.createReadStream("./a.txt")
let ws = fs.createWriteStream("./b.txt")
rs.pipe(ws)
// 根据流生成了b.txt
Readable
const fs = require("fs")
let rs = fs.createReadStream("./a.txt")
// readStream
rs.pipe(process.stdout)
// print :"stream read write pipe"%
Readable 的两种模式
- 暂存模式
readale事件监听,会把数据直接放进缓存中 - 流动模式
data 事件,会直接读取流的内容,不需要进入缓存查找
const { Readable } =require("stream")
let source = ['ll','kk','nn']
class myReadable extends Readable {
constructor(source){
super()
this.source = source
}
// 必须_read ,这样才能重新read
_read(){
const data = this.source.shift()||null
this.push(data)
}
}
let Readablem = new myReadable(source)
Readablem.on("readable",()=>{
while((data = Readablem.read())!=null){
// 第一次会打印出来 ll kk ,因为,ll 最开始就在缓存里
console.log(data.toString())
}
})
Readablem.on("data",(chunk)=>{
console.log(chunk.toString(),"chunk")
})
writable
const { Writable } = require("stream")
class myWritable extends Writable {
constructor(){
super()
}
_write(chunk,en,done){
process.stdout.write(chunk.toString()+"---wirtable")
process.nextTick(done)
}
}
let myw = new myWritable()
myw.write("lllllkkkkk","utf-8",()=>{
console.log("end")
})
duplex
const { Duplex } = require("stream")
class myDuplex extends Duplex {
constructor(source){
super()
this.source = source
}
_read(){
let data = this.source.shift()||null
this.push(data)
}
_write(chunk,en,done){
process.stdout.write(chunk.toString())
process.nextTick(done)
}
}
let myduplex = new myDuplex(["a","b","c"])
myduplex.write("aaakkk",(chunk)=>{
console.log(chunk,"wirite")
})
myduplex.on("data",(chunk)=>{
console.log(chunk.toString(),"data")
})
transform
const { Transform } = require("stream")
class MytransForm extends Transform {
constructor(){
super()
}
_transform(chunk,en,next){
this.push(chunk.toString().toUpperCase())
next()
}
}
let mytransfor = new MytransForm()
mytransfor.write("dddd")
mytransfor.on("data",(chunk)=>{
console.log(chunk.toString(),"chunk") // DDDD
})
transform 中即可读写,而duplex 读写是分开的,不能相互影响
readStream
rs = fs.createReadStream("./a.txt",{
flags:"r", // 读
encoding:null,// 压缩
fd:null ,// 文件索引
mode:438 ,// 读取文件权限
autoClose:true,//是否自动关闭
start:0, //开始位置
// end:3 , // 结束位置
highWaterMark:1 // 单词read 最多的值
})
// rs.on("readable",(chunk)=>{
// while((data = rs.read())!=null){
// console.log(data.toString(),"data")
// }
// })
rs.on("data",(chunk)=>{
console.log(chunk.toString())
rs.pause() // 使用状态暂停
setTimeout(()=>{
rs.resume() // 每隔一秒 使 steam 变的流动
},1000)
})
- open
- data
- end
- close
- err
rs = fs.createReadStream("./a.txt",{
flags:"r", // 读
encoding:null,// 压缩
fd:null ,// 文件索引
mode:438 ,// 读取文件权限
autoClose:true,//是否自动关闭
start:0, //开始位置
// end:3 , // 结束位置
highWaterMark:1 // 单词read 最多的值
})
// rs.on("readable",(chunk)=>{
// while((data = rs.read())!=null){
// console.log(data.toString(),"data")
// }
// })
let bufferArr = []
rs.on("data",(chunk)=>{
console.log(chunk.toString())
bufferArr.push(chunk)
rs.pause() // 使用状态暂停
setTimeout(()=>{
rs.resume() // 每隔一秒 使 steam 变的流动
},1000)
})
rs.on("open",()=>{
console.log("open")
})
rs.on("end",(chunk)=>{
bufferArr.concat(chunk)
console.log(bufferArr.toString(),"bufferArr")
console.log("end")
})
rs.on("close",()=>{
console.log("close")
})
rs.on("error",()=>{
})
/*
open
0
1
2
3
4
5
6
7
8
9
0,1,2,3,4,5,6,7,8,9 bufferArr
end
close
writeSteam
ws = fs.createWriteStream('./wab.txt')
ws.write("dsss",()=>{
console.log("write")
})
ws.on("open",()=>{
console.log("open")
})
ws.on("close",()=>{
console.log("close")
})
ws.end("end 终止,使得会 close,但是end后不能在 write")
// ws.write("wri hou")
ws.on("error",(err)=>{
console.log(err)
})
/*
open
write
close
*/
wtrite 执行流程
let ws = fs.createWriteStream("./wab.txt",{
flag:"w",
encoding:null,
mode:438,
fd:null,
highWaterMark:4,
autoClose:true
})
let flag = ws.write("1")
console.log(flag)
flag = ws.write("2")
console.log(flag)
flag = ws.write("3")
console.log(flag)
flag = ws.write("3")
console.log(flag)
flag = ws.write("3")
console.log(flag)
flag = ws.write("3")
console.log(flag)
flag = ws.write("3")
console.log(flag)
flag = ws.write("3")
console.log(flag)
/*
true
true
true
false
false
false
false
false
*/
highWaterMark:4,设置缓存为长度为4的,如果写入的值大于内存中的值flag 就为false。
缓存清空后 监听操作
ws.on("drain",()=>{
console.log("缓存开")
})
分批写入文件
const fs = require("fs")
let ws = fs.createWriteStream("fenpi.txt",{
highWaterMark:1
})
let fleg = true
let source = "abcd"
let num = 0
function writeFp(mark) {
fleg = mark||fleg
while(fleg&&num!=source.length){
fleg = ws.write("1")
num+=1
}
}
writeFp()
// 监听有缓存有数据时
ws.on("drain",()=>{
writeFp(true)
})
pipe 可以帮我们实现
背亚机制
const fs = require("fs")
const rs = fs.createReadStream("./a.txt",{
highWaterMark:4
})
const ws = fs.createWriteStream("./fenpi.txt")
let flag = false
rs.on("data",(chunk)=>{
flag = ws.write(chunk)
console.log(flag)
if(!flag){
rs.paused()
}
})
ws.on("drain",()=>{
rs.resume()
})
// 上面和下面一样的机制
rs.pipe(ws)
http
服务器和 客户端服务
server
const http = require("http")
const url = require("url")
const querystring = require("querystring")
const server = http.createServer((req,res)=>{
// req ,res 继承了steam
const {pathname,query} = url.parse(req.url)
console.log(querystring.parse(req.url),"querystring")
console.log(pathname,"pathName")
console.log(query,"query")
let resList = []
req.on("data",(chunk)=>{
resList.push(chunk)
})
req.on("end",()=>{
let data = Buffer.concat(resList).toString()
console.log(data,"data")
if(req.headers["content-type"]=="application/json"){
let val = JSON.parse(data)
val.qq = "1129557848"
res.end(JSON.stringify(val))
}
})
})
server.listen(3039,()=>{
console.log("服务启动")
})
client-server
const http = require("http")
let options={
host:"localhost",
path:"/home?a=1&b=1",
port:3039,
method:"GET",
headers:{
"Content-Type":"application/x-www-form-urlencoded"
}
}
// let req = http.get(options,(res)=>{
// console.log(res)
// })
// req.end("dddd")
let requestOption = {
host:"localhost",
port:3039,
path:"/index?m=1&d=1",
method:"POST",
headers:{
"Content-Type":"application/json"
}
}
let requestReq = http.request(requestOption,(res)=>{
// req ,res 继承了steam
let reslist = []
res.on("data",(v)=>{
reslist.push(v)
})
res.on("data",()=>{
console.log(Buffer.concat(reslist).toString()
) })
})
requestReq.end(JSON.stringify({a:1,b:2}))