1 buffer
- 不需要require 的全局變量
- 讓node 使用二進(jìn)制數(shù)據(jù)操作
- 不占用v8的內(nèi)存,可以使用node管理
- 一般steam流使用,充當(dāng)緩存區(qū)域---文件讀寫
alloc
創(chuàng)建指定大小的buffer
let buffer = Buffer.alloc(10) // 10 字節(jié)
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 無法觸發(fā)
let b3 = Buffer.from([1,2,Buffer.from("abc")]) //
let b4 = Buffer.from("中").toString()
console.log(b2)
console.log(b3)
console.log(b4)
allocUnsafe
創(chuàng)建指定大小的buffer(不安全)
from
接收數(shù)據(jù)創(chuàng)建buffer
buffer的靜態(tài)方法
// fill
let bf = Buffer.alloc(6)
bf.fill("123")
console.log(bf) // 結(jié)果 <Buffer 31 32 33 31 32 33> 默認(rèn)填滿
let bf1 = Buffer.alloc(6)
bf1.fill("123",1,4) //<Buffer 31 32 33 31 32 33> 從第一位開始到第4位置結(jié)束
console.log(bf1)
// write
let bf = Buffer.alloc(6)
bf.write("123")
console.log(bf) // 結(jié)果 <Buffer 31 32 33 00 00 00> 不會(huì)默認(rèn)填滿
let bf2 = Buffer.alloc(6)
bf2.write("123",1,3) // <Buffer 00 31 32 33 00 00> 從第一位開始到第3位置結(jié)束
console.log(bf2)
// toString 轉(zhuǎn)換ask嗎到字符
console.log(bf2.toString())
write 和fill的區(qū)別是,fill主動(dòng)填滿內(nèi)存,write不會(huì)
slice像數(shù)組slice 實(shí)例
let bf = Buffer.from("DDD")
console.log(bf.slice(2,3).toString())
copy 實(shí)例方法
let bf1 = Buffer.alloc(6)
let bf2 = Buffer.from("拉鉤")
bf2.copy(bf1,3,3,6) // 第一個(gè)3 值得是b2往左的偏移量,第2個(gè)是copy的起始位,6是結(jié)束位置
console.log(bf1.toString())
console.log(bf2.toString())
concat 靜態(tài)方法
let a = Buffer.from("111")
let b = Buffer.from("222")
console.log(Buffer.concat([a,b],5).toString()) // concat 將兩個(gè)buffer 合并, 5是限制長度
isBuffer 靜態(tài)方法
let a = Buffer.from("111")
console.log(Buffer.isBuffer(a))
module.export 和 export 的不同
module.export 和 export的地址是執(zhí)行一個(gè)地方
let name1 = "jack"
let getName = () => {
return name1
}
// module.exports = {
// name1,
// getName
// }
// 上面等于 exports.name1= name1
// exports.getName= getName
// 但是不能把 exports={name:111},因?yàn)?exports.name1 = name1
exports.getName = getName
console.log(module, "modulePage")
module 對(duì)象數(shù)據(jù)
Module {
id: '/Users/liukun/Desktop/node/common/module.js', // 當(dāng)前文件夾
path: '/Users/liukun/Desktop/node/common', // 調(diào)用的位置
exports: { name1: 'jack', getName: [Function: getName] }, // 導(dǎo)出
parent: Module { // 父級(jí)
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 補(bǔ)足查找
'/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
- 查詢文件系統(tǒng)(有可能查緩存)node查找位置 以 .js .json .node 補(bǔ)足查找
- 加載所有文件js(字符串)---readfileSync
- 執(zhí)行所有文件(字符串轉(zhuǎn)為js),然后包裝module.export 掛載內(nèi)容
如何執(zhí)行 字符串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 事件隊(duì)列
- timer 執(zhí)行settimeout
- pendding callbacks 執(zhí)行系統(tǒng)操作的回調(diào)例如 tcp udp
- ide,prapare 只在系統(tǒng)內(nèi)部使用
- poll 執(zhí)行i/o相關(guān) 例如 文件讀寫
- check 執(zhí)行setImmediate中的回調(diào)
- close callbacks 執(zhí)行close相關(guān)事件
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事件循環(huán)和瀏覽器的區(qū)別
- node有6個(gè)事件
- 瀏覽器只有宏偉任務(wù)
node事件循環(huán)的問題
setImmediate(() => {
console.log("setImmediate")
})
setTimeout(() => {
console.log("setTimeout")
})

image.png
會(huì)發(fā)現(xiàn)有時(shí)答案相反:原因setTimeout 后面的時(shí)間定時(shí)器的值不寫為0的時(shí)候照成的,有時(shí)候會(huì)對(duì)時(shí)間計(jì)算錯(cuò)誤
問題
const fs = require("fs")
fs.readFile("./a.txt", () => {
setImmediate(() => {
console.log("setImmediate")
})
setTimeout(() => {
console.log("setTimeout")
})
})
// setImmediate setTimeout
應(yīng)為在 執(zhí)行poll 的io隊(duì)列后會(huì)去執(zhí)行 chek 隊(duì)列的setImmediate 。按照隊(duì)列順序往下走
stream 流
- readable 可讀流,能夠?qū)崿F(xiàn)數(shù)據(jù)的讀取
- writeable 可寫流,能夠?qū)崿F(xiàn)數(shù)據(jù)的寫入
- duplex 雙工流,可以實(shí)現(xiàn)數(shù)據(jù)的讀寫
- transform 轉(zhuǎn)換流??梢詫?shí)現(xiàn)數(shù)據(jù)的讀寫,并且可以進(jìn)行轉(zhuǎn)換
并且 stream 模塊 實(shí)現(xiàn)了4個(gè)具體抽象
所有的stream 都繼承了EventEmitter
const fs = require("fs")
let rs = fs.createReadStream("./a.txt")
let ws = fs.createWriteStream("./b.txt")
rs.pipe(ws)
// 根據(jù)流生成了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事件監(jiān)聽,會(huì)把數(shù)據(jù)直接放進(jìn)緩存中 - 流動(dòng)模式
data 事件,會(huì)直接讀取流的內(nèi)容,不需要進(jìn)入緩存查找
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){
// 第一次會(huì)打印出來 ll kk ,因?yàn)?,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 ,// 讀取文件權(quán)限
autoClose:true,//是否自動(dòng)關(guān)閉
start:0, //開始位置
// end:3 , // 結(jié)束位置
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() // 使用狀態(tài)暫停
setTimeout(()=>{
rs.resume() // 每隔一秒 使 steam 變的流動(dòng)
},1000)
})
- open
- data
- end
- close
- err
rs = fs.createReadStream("./a.txt",{
flags:"r", // 讀
encoding:null,// 壓縮
fd:null ,// 文件索引
mode:438 ,// 讀取文件權(quán)限
autoClose:true,//是否自動(dòng)關(guān)閉
start:0, //開始位置
// end:3 , // 結(jié)束位置
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() // 使用狀態(tài)暫停
setTimeout(()=>{
rs.resume() // 每隔一秒 使 steam 變的流動(dòng)
},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 終止,使得會(huì) close,但是end后不能在 write")
// ws.write("wri hou")
ws.on("error",(err)=>{
console.log(err)
})
/*
open
write
close
*/
wtrite 執(zhí)行流程
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,設(shè)置緩存為長度為4的,如果寫入的值大于內(nèi)存中的值flag 就為false。
緩存清空后 監(jiān)聽操作
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()
// 監(jiān)聽有緩存有數(shù)據(jù)時(shí)
ws.on("drain",()=>{
writeFp(true)
})
pipe 可以幫我們實(shí)現(xiàn)
背亞機(jī)制
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()
})
// 上面和下面一樣的機(jī)制
rs.pipe(ws)
http
服務(wù)器和 客戶端服務(wù)
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("服務(wù)啟動(dòng)")
})
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}))