node.js学习笔记

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")
})
image.png

会发现有时答案相反:原因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}))
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,258评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,335评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,225评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,126评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,140评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,098评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,018评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,857评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,298评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,518评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,400评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,993评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,638评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,661评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容