《新时期的Node.js入门》
作者 李锴 出版社 清华大学出版社
ISBN 9787302487807 出版时间 2018.1
豆瓣网址 https://book.douban.com/subject/30170564/ 是否有电子版 微信读书
阅读日期 2020-6-25 更新日期
相关链接 备注 github

如果你想读这本书,使用微信扫码即可:

image.png

全书结构如下:

《新时期的Node.js入门》常用模块 - 图2本书的第二章深入浅出解释了一下常用的内置模块,可供简单了解。

我后续可以继续补充完善。

常用模块

《新时期的Node.js入门》常用模块 - 图3

Module

还是 CommonJS AMD ES 三种模块方案。

CommonJS

Node早于es模块发布之前,所以选用了CommonJS,特点是同步加载代码,不适合web中使用。
每个文件是一个模块,必须通过 exports require 导入导出

  1. // export
  2. var person={}
  3. module.exports = person
  4. // require
  5. var persion = require('./xx')

为什么cjs里的require是同步?这里有一个重复引入的概念:第一次引入之后会留在缓存中,后续使用会直接使用缓存。一个可能是公共依赖的模块,尽可能要一步到位加载完成。缓存的好处很多,足以抵过以外重启带来的性能损失。

缓存是依赖路径的。

引入未知的模块要保持警惕,如果一个模块中使用了定时器、循环、连接数据库等,可能会导致内存泄露。

node模块中的this指向什么: module.exports ,这个后面再补充。模块作用域:

  1. (function(exports,require,module,__filename,__dirname){
  2. })()

Buffer

  • buffer 是node的数据类型,用来处理二进制数据
  • 前端es6+增加了ArrayBuffer用来操作二进制数据

一般fs读写,网络操作,默认返回的Buffer

  1. var buffer = new Buffer([0x48])
  2. var buffer = new Buffer('hello')
  3. console.log(buffer)
  4. // 注意这种写法已经被弃用,后面统一使用 Buffer.from
  5. var buffer = Buffer.from([0x48])
  6. var buffer = Buffer.from('hello')
  7. buffer.toString('utf-8',0,5) // 默认就是utf-8

当我们用buffer去读一个汉字,会发现一个汉字占用三个字节。注意这里的3,后面要考。

Buffer 的一个常见处理场景,是处理http的post请求,比如下载一个文件

  1. var body = ''
  2. req.setEncoding('uft8')
  3. req.on('data',chunk=>body+=chunk)
  4. req.on('end',()=>{})

这里的 body += chunk 实际上是 body+=chunk.toString() ,如果是英文没关系,如果有中文,这里默认是 utf-8 可能会乱码。

highWaterMark 最高水平线,表示内部缓存区最多容纳的字节数,超出的就会停止读取文件,默认64k

如果一个100k的文件,默认读取,会分成 64+36触发两次data事件,然后触发end事件。如果hightWaterMark 设置过小,会多次调用,影响性能。

刚才一个汉字utf-8占用三个字节,如果 highWaterMark =10`,会除不开,打印时候就会有乱码。

上面的 += 写法已经过时,现在要求使用 Push

  1. var data=[]
  2. req.on('data',chunk=>data.push(chunk))
  3. req.on('end',()=>{
  4. var buf = Buffer.concat(data)
  5. // log buf.toString()
  6. })

放入数组,后面再转换

FS

很多api

fs.promises 一套走。

readFile

适合体积较小的文件,如果文件尺寸大,建议使用 stream。

fs.writeFile 写文件

fs.stat

fs.stat文件状态,建议先先判断是否存在stat,再open或者read或者write
有一个 fs.fstat ,和stat的区别是,fstat的第一个参数是文件描述符,通常搭配open使用

其他略

http

也简单过 http.createServer
定义了 connection request 事件

res对象

  1. // setHeader 单个设置
  2. responese.setHeader('Content-Type','application/json')
  3. // 多个header使用 writeHead

tcp

Socket是对tcp协议的一种封装方式。忽略

什么是https SSL

ssl是独立的,和http结合是https,和webSocket是wss

ssl和tls差异很小,一般不需要做区分

localhost利用OpenSSL 这里忽略

WebSocket

使用过 socket.io封装库

Stream

  1. var stream = require('stream')

四种基础stream类型:

  • readable 可读流 fs.createReadStream()
  • writable 可写流 fs.createWriteStream()
  • duplex 可读可写 net.Socket
  • transform 操作写入的数据,读取结果,用于输入和输出不要求匹配的场景

主要是前两种

  1. var stream = require('stream')
  2. var fs = require('fs')
  3. var readStream = fs.createReadStream('./a.txt','utf-8')
  4. readStream.on('data',data=>console.log(data))
  5. readStream.on('close',()=>{})
  6. readStream.on('error',()=>{})

在 writeable stream 中有 drain 事件
如果我们有一个读写流,通过pipe给可写流,如果读写速度快,会等待可写,在内存中缓存,大小也是有HigtWaterMark 限制的。超出缓存,读写会暂停,等到缓存区清空,触发 drain

多进程服务

单线程线程崩溃会导致程序退出,也无法充分利用多核cpu,提供了 child_process 模块来实现多进程的支持。

child_process:

  • exec
  • spawn 最基础,其他多多少少借助这个api
  • fork
  • execFile

为了统一node创建多进程的服务方式,后续新增了 cluster 模块,可以看做封装了 child_process

cluster.fork cluster.isMaster 是主从模式