File System
fs.access
判断对一个文件是否有权限, 参数为 filename 和 mode :
fs.constants.F_OK:在当前进程存在与否fs.constants.R_OK:读取fs.constants.W_OK:写入fs.constants.X_OK:执行try {fs.accessSync('etc/passwd', fs.constants.R_OK | fs.constants.W_OK);console.log('can read/write');} catch (err) {console.error('no access!');}
HTTP
http.Agent
Agent用来为 http 客户端管理连接的持久性和复用性。对于同一个 host 和 port,Agent 维护了一个进行中的请求的队列,其中的每个请求都会复用同一个 socket connection 。当队列为空时,这个 socket connection 会被销毁或者放入到 socket 池中,以供后续对同一个 host 和 port 的请求使用。销毁或者放入池中取决于keepAlive选项。
对于放入池中的链接,默认启用了 TCP 的 Keep Alive,但是如果服务器关掉了空闲的连接,池中的连接会被移除,此后对于同一个 host 和 post 的 http 请求,会重新建立新的连接。 服务器也可能拒绝多个请求使用同一个 socket connection,此时每个请求就必须建立新的连接,并且不能将连接放入池中。
当服务器或者客户端关闭了连接之后,该连接会被移除连接池。任何已经不被使用的 socket 将被销毁,以避免在没有请求时保持 Node.js 进程运行。
对于不使用的 Agent 实例,最好是 destroy 它,不使用的 socket 会消耗操作系统的资源。
如果一个 socket 发出了 close 或 agentRemove 事件,它将被移出 Agent .如果想长时间保持一个 request 开启,但不想把它放在 Agent 里面,可以使用如下代码:
http.get(options, (res) => {// Do stuff}).on('socket', (socket) => {socket.emit('agentRemove');});
Buffer
感觉把API挨个写出来没啥意义,还浪费时间。改为看文档吧,多看几遍并经常复习总会烂记于心。
Nodejs中 Buffer 用来以字节序列的方式展现二进制数据。Buffer 是 Uint8Array 的子集,存放的都是0~255的整数,但是 Buffer 所占的内存空间已经分配不可改变。
在进行与字符串的相互转化时可以指定编码格式:
const buf = Buffer.from([ '3', 'hello' ]);buf.toSting('utf8');
支持的编码格式如下:
utf8utf16le, 与ucs2相同latin1, 与binary相同base64asciihex
常用API介绍
类方法
Buffer.from
Buffer.from(array)Buffer.from(buffer)Buffer.from(string, encoding), 默认utf8- Buffer.from(arrayBuffer, offset, length)
- Buffer.from(Object, offsetOrEncoding, length)
const buffer = Buffer.from('888338', 'utf8');
Buffer.alloc(size, fill, encoding)
创建 Buffer 实例,分配内存,并初始化其中的数据
Buffer.allocUnsafe(size)
创建实例,分配内存,但不初始化,有可能含有旧的数据
Buffer.allocUnsageSlow(size)
一般分配内存时,如果大小小于4KB,则是从事先分配好的内存池中分配,这样可以避免重复的垃圾回收,就是直接分配内存,而不是从事先分配好内存池中分配。
Nodejs 会事先分配一块内存池供使用,需要的内存都从这个地方分配,可以避免垃圾回收因为过多的内存块而过度使用。这样可以消除了追踪和清理工作,提高了性能。
Buffer.byteLength(string, encoding)
查询数据的字节长度,可以传入 string、ArrayBuffer、ArrayBuffer、Array、Buffer等
Buffer.isEncoding(encoding)
是否某个编码是否支持。如果是支持的,返回 true
Stream
https://github.com/jabez128/stream-handbook
child_process
spawn
spawn 衍生一个新的进程,用来执行传入的命令。可以通过返回的子进程的 stdout 来监听命令执行的输出。
import { spawn } from "child_process"/*** https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options* 第二个参数可以是命令的参数,也可以没有* 第三个参数传入 options* - cwd* - env* - stdio* - detached: 指定子进程独立于父进程运行* - shell: 如果为 true,会在一个 shell 中运行命令,也可以通过字符串指定一个不同的 shell,*/const ls = spawn('ls', [ '-lh', '.' ], {cwd: process.cwd(),env: process.env,argv0: '-lh',detached: true,uid: undefined,gid: undefined,serialization: 'advanced',})ls.stdout.on('data', data => {console.log(`stdout: ${data}`)})ls.stderr.on('data', data => {console.log(`stderr: ${data}`)})/*** 一旦子进程成功衍生,不论内部执行是否出错,都会触发本事件,否则触发 `error`* 总是最先触发,早于其它事件和 stdout 和 stderr 事件*/ls.on('spawn', () => {console.log('spawn');})/*** 子进程通过 process.send() 发送消息时会触发此事件,* message: 对象* sendHandler: A net.Socket or net.Server object, or undefined.*/ls.on('message', (message, sendHandler) => {console.log(message, sendHandler);})/*** 当进程结束时抛出,此时 stdio 可能还没有断开* 如果是通过新号关闭的,则第二个参数会是字符串,否则是 null*/ls.on('exit', (code, signal) => {console.log('exit: ', code)})/*** 当进程结束且 stdio 都关闭时抛出,总是在 exit 或者 error 事件之后* signal 为结束时的信号*/ls.on('close', code => {console.log('close:', code)})/*** 调用 subprocess.disconnect() 或者在子进程内调用 process.disconnect()*/ls.on('disconnect', () => {console.log('disconnect');})/*** error 事件的触发:* 1. spawn 失败* 2. kill 失败* 3. send message 失败** error 事件之后,exit 事件可能会或不会触发,需要防止同样的事件处理器调用两次*/ls.on('error', () => {console.log('error')})
exec
child_process.exec(command[, options][, callback])
衍生一个 shell 然后执行传入的命令。exec 缓存命令执行的输出,然后传入到回调中,所以只适合数据量比较小的命令。
execFile
child_process.execFile(file[, args][, options][, callback])const { execFile } = require('child_process');const child = execFile('node', ['--version'], (error, stdout, stderr) => {if (error) {throw error;}console.log(stdout);});
execFile用来执行一个可执行文件或者命令,可以传入参数。
与 exec 类似,但是 execFile不会默认衍生一个shell,而是直接衍生一个进程,所以会比 exec更加高效。
fork
child_process.fork(modulePath[, args][, options])
- child_process fork 属于 spawn 的一种特殊用法,会默认衍生一个 Nodejs 进程并执行给定的模块或文件。
- 子进程内置了 IPC 通道,可以和父进程进行通信
- 子进程独立于父进程,会分配额外的资源,所以不建议衍生太多进程
- execPath 默认与父进程的相同,可以进行指定
