总结NodeJS常用的API,重点地方有笔者的释义以及详细说明。关联度高的模块放一起叙述,并有对比说明,比如buffer与fs,stream与http,process与child_process。本文尽量做到兼具实用与API广度,更多详细内容请看Node.JS官网文档(opens new window)。
path(opens new window)
- __filename。全局值,当前文件绝对路径
- dirname。全局值,当前文件夹绝对路径。等效于path.resolve(filename, ‘..’)
- path.join([…paths])。相当于把所传入的任意多的参数 按照顺序 进行命令行般的推进
- path.resolve([…paths])。以当前文件的路径为起点,返回绝对路径。可以理解为每次都是新建cd命令
- path.dirname(path)。返回指定路径所在文件夹的路径
- path.basename(path)。返回指定Path路径所在文件的名字
- path.extname(path)。获取指定字符串或者文件路径名字的后缀名,带.比如.txt
path.isAbsolute(path) 是否是绝对路径,返回boolean值
path(opens new window)
__filename。全局值,当前文件绝对路径
__dirname。全局值,当前文件夹绝对路径。等效于path.resolve(__filename, '..')
path.join([...paths])。相当于把所传入的任意多的参数 按照顺序 进行命令行般的推进
path.resolve([...paths])。以当前文件的路径为起点,返回绝对路径。可以理解为每次都是新建cd命令
path.dirname(path)。返回指定路径所在文件夹的路径
path.basename(path)。返回指定Path路径所在文件的名字
path.extname(path)。获取指定字符串或者文件路径名字的后缀名,带.比如.txt
path.isAbsolute(path) 是否是绝对路径,返回boolean值
url(opens new window)
url 模块提供了两套 API 来处理 URL 字符串:一个是Node.js特有的API,是旧版本的遗留;另一个则是实现了WHATWG URL Standard的 API (const {URL} = require(‘url’)方式),该标准也在各种浏览器中被使用。
旧版url api,新版URL Standard见这(opens new window):url.parse(urlString[, parseQueryString[, slashesDenoteHost]])。把url字符串解析为url对象
- host
- hostname
- href
- path
- pathname
- port
- protocol
- query
- search ```json const url = require(‘url’); const myURL = url.parse(‘https://example.org/foo?type=123#123‘); console.log(myURL) / Url { protocol: ‘https:’, slashes: true, auth: null, host: ‘example.org’, port: null, hostname: ‘example.org’, hash: ‘#123’, search: ‘?type=123’, query: ‘type=123’, pathname: ‘/foo’, path: ‘/foo?type=123’, href: ‘https://example.org/foo?type=123#123‘ } /
- url.format(urlObject)。把url对象解析为字符串
- url.resolve(from, to)。以一种 Web 浏览器解析超链接的方式, 基于一个基础 URL,对目标 URL进行解析。查看其源码实现:
```json
Url.prototype.resolve = function(relative) {
return this.resolveObject(urlParse(relative, false, true)).format();
};
querystring
- querystring.parse。一个URL查询字符串 str 解析成一个键值对的集合。 ```json const querystring = require(‘querystring’) let query = querystring.parse(‘type=123’) console.log(query) // { type: ‘123’ }
- querystring.stringify。遍历给定的 obj 对象的自身属性,生成 URL 查询字符串。
<a name="jqRU1"></a>
## [Stream](https://lq782655835.github.io/blogs/node/node-usage-api-summary.html)
**Node中很多数据结构都继承自Stream**。Stream在文件系统和http请求中,有非常大的作用。
- 对于文件处理,小文件对于buffer数据结构能很好的解决,直接将文件所有数据加载到内存中;但对于大文件,buffer这种方式不可取,容易打爆内存。最好的方式是像流水一样,将读取的数据实时流入到写入的文件,直到数据全部读完并写入好对应目标文件。举个例子,就像两个水池,待读取的文件是一个装满水的池子,写入的空文件是一个等待蓄满水的空池子。通过Stream API的方式,将两个池子嫁接起来,使得满水的池子可以持续注水到空池子中。而且Stream继承自EmitEvents,过程中会有许多回调事件发出,供开发人员自定义内容。
- 对于http请求处理,最常见的就是通过流去写入内容。
以下对象继承了可读流:
- **HTTP responses, on the client**
- **HTTP requests, on the server**
- **fs read streams**
- **child process stdout and stderr**
- **process.stdin**
- zlib streams
- crypto streams
- TCP sockets
<a name="ljAUn"></a>
### **<br />Stream类**
- stream.Writable
- **write()** 写入数据到流
- **end()** 表明已没有数据要被写入
- Events
- **drain**。 每个数据块写入成功后回调事件,可能多次触发。
- pipe。当readableStream.pipe()调用时回调事件
- finish。 当writeableStream.end()调用并数据读完后回调事件。
- close
- error
- stream.Readable
- pipe(destination:stream.Writable, options) 把可读数据流入可写流中
- pause() 流暂停。使读取流暂停emit 'data'事件
- resume() 流重启。重新开始emit 'data'事件
- unpipe()
- Events
- **data**。每次读取完一段数据块回调事件,可能多次触发。
- readable。数据读取可用时回调事件。
- **end**。 数据全部读取完成回调事件。
- close
- error
- stream.Duplex
- stream.Transform
以下举一个完整例子:
```json
const fs = require('fs')
let readStream = fs.createReadStream('./node/snapshot/test1.png')
let writeStream = fs.createWriteStream('./node/snapshot/test1-copy.png')
readStream
.on('data', (chunk) => {
// 当读取较大文件时,写入流的速度可能没有读入的速度快
// 所以这里做了一个处理,没写完暂停读入流
if (writeStream.write(chunk) === false)
readStream.pause()
})
.on('end', () => writeStream.end())
// 这里配合上面pause,写完了继续读入流
writeStream.on('drain', () => readStream.resume())
// 以上换成管道的方式,只需一行代码:readStream.pipe(writeStream)
http
- http.Server。http.createServer(function(req, res){})返回该类实例。
- listen()
- http.IncomingMessage。 请求类。http.createServer回调函数中req参数即是该类的实例。
- headers
- accept
- host
- cookie 未经过处理的cookie字符串,所以一般需要cookie-parse等第三方包处理
- referer
- url
- method
- headers
- http.ServerResponse。Node作为服务端。http.createServer回调函数中res参数即是该类的实例。
- 可写流
- write(chunk[, encoding][, callback])
- end([data][, encoding][, callback])
- 如果带data数据,相当于response.write(data, encoding) + response.end(callback)
- setHeader(name, value) 设置name头信息。所有HTTP消息头(opens new window)
- Content-Type。所有Content-Type(opens new window)
- application/json
- text/html
- text/plain
- text/xml
- application/x-www-form-urlencoded
- multipart/form-data。常用来上传图片等数据
- Content-Length
- Access-Control-Allow-Origin
- Access-Control-Allow-Headers
- Access-Control-Allow-Methods
- Access-Control-Allow-Credentials
- X-Powered-By
- Content-Type。所有Content-Type(opens new window)
- getHeader(name) 获得name指定头信息
- writeHead(statusCode[, statusMessage][, headers]) 设置头信息,包括状态码
- http.ClientRequest。Node作为客户端。http.get()/http.request()返回该类。
- 可写流。跟http.ServerResponse有些类似
- write(chunk[, encoding][, callback])。stream继承,请求写入数据,一般是POST请求需要。
- end([data][, encoding][, callback])。stream继承,请求发出。
- setHeader(name, value) 设置name头信息
- getHeader(name) 获得name指定头信息
- 回调函数res参数是可读流
IncomingMessage对象是由http.Server或http.ClientRequest创建的
// Node作为客户端发送请求
const postData = querystring.stringify({
'msg': 'Hello World!'
});
const options = {
hostname: 'www.google.com',
port: 80,
path: '/upload',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(postData)
}
};
const req = http.request(options, (res) => {
// 响应值res作为从目标接口中获取到的值,是个readable.Stream
res.setEncoding('utf8');
res.on('data', (chunk) => console.log(`BODY: ${chunk}`));
res.on('end', () => console.log('No more data in response.'));
});
req.on('error', (e) => {
console.error(`problem with request: ${e.message}`);
});
// req作为客户端请求,是个writeable.Stream。
req.write(postData); // 带上参数
req.end(); // 结束写入,开始发送请求。如果是http.get() API会自动带req.end()
// Node作为服务端,res(response)参数继承的是writeable.Stream
const http = require('http')
http.createServer((req, res) => {
res.write('hello world')
res.end()
}).listen(3001)
http.get()与 http.request() 唯一的区别是它设置请求方法为 GET 且自动调用 req.end()
在node是客户端的时候,req是从node这边发起的,是可写流,res是从外边响应的,是可读流。
在node是服务端的时候,req是从客户端发起的,是可读流,res是从node响应的,是可写流。
Bufferglobal
在 TCP 流或文件系统操作等场景中处理字节流。Buffer 类是一个全局变量。Buffer 类的实例类似于整数数组,但 Buffer 的大小是固定的、且在 V8 堆外分配物理内存。 Buffer 的大小在创建时确定,且无法改变。
Node.js v6.0.0 之前,Buffer 实例是通过 Buffer 构造函数创建的,它根据参数返回不同的 Buffer。为了使 Buffer 实例的创建更可靠,new Buffer() 构造函数已被废弃,建议使用 Buffer.from()、Buffer.alloc()和 Buffer.allocUnsafe()
- 创建Buffer
- new Buffer(number/string/array)Deprecated。推荐使用 Buffer.from(array/string) 和Buffer.alloc(size)代替。
- Buffer.from(array/string)
- Buffer.alloc(size)
- Buffer静态方法
- Buffer.isBuffer(obj)
- Buffer.byteLength(string)
- Buffer.concat()
- Buffer.compare()
- Buffer实例
- length
- toString() buffer转为string
- write(string, offset=0, length, encoding=’utf8’)。对buffer对象写入string
- copy()
- slice()
- compare()
- equals()
- fill() ```json let buf = new Buffer(‘hello world’) // 初始化之后,实例buf长度无法改变 console.log(buf.length, buf.toString()) // 11, hello world
buf.write(‘temp’) console.log(buf.length, buf.toString()) // 11, tempo world
buf.write(‘01234567891234567890’) console.log(buf.length, buf.toString()) // 11, 01234567891
<a name="bMpiL"></a>
## [File System(opens new window)](https://nodejs.org/dist/latest-v11.x/docs/api/fs.html)
- file文件操作
- **readFile(path[, options], callback)**
- 没有指定 encoding,则返回原始的 buffer
- **writeFile(file, data[, options], callback)**
- 如果文件已存在,则覆盖文件。
- data支持 string/Buffer/TypedArray/DataView
- data 是一个 buffer,则忽略 encoding
- copyFile(src, dest[, flags], callback)
- rename(oldPath, newPath, callback)。文件重命名
- write(fd, string[, positinon[, encoding]], callback)。将 string 写入到 fd 指定的文件写文件
- exists(url, callback(boolean))Deprecated。查询是否存在,一般用在单纯检查文件而不去操作(open/readFile/writeFile等操作文件不成立时会回调err)文件时。推荐使用fs.stat() or fs.access() 代替该方法。
- **stat(path[, options],callback(err, stat))**。查询文件/目录信息
- stat.isFile 是否一个普通文件
- stat.isDirectory 是否一个目录
- stat.ctime 最后一次修改文件的时间
- createReadStream(path[, options])。 指定路径读取,获得Readable Stream。
- createWriteStream(path[, options])。创建空的写入流到目标路径,获得Writeable Stream。
- dir目录操作
- **readdir(path[, options], callback)**。读目录,获取目录下的所有文件和文件夹名称。
- rmdir(path, callback)。移除目录
文件操作的path参数,绝对路径和相对路径都支持(相对路径基于process.cwd())。
```json
const fs = require('fs')
const path = require('path')
let dir = './node/snapshot'
fs.readFile(path.join(dir, 'test1.png'), (err, data) => {
console.log(Buffer.isBuffer(data)) // true
fs.writeFile(path.join(dir, 'test1_copy.png'), data, (error) => console.log(error)
})
Process(opens new window)global
process对象是一个提供当前node进程信息的全局对象,所以该对象不需要require()引入。process同时也是EventEmitter(opens new window)(典型的发布订阅模式案例)的一个实例,所以有.on()等方法。
- process.argv。一个包含命令行参数的数组。第一个元素是’node’,第二个元素是JavaScript文件的文件名。接下来的元素则是附加的命令行参数。 ```json // process.js process.argv.forEach(function(val, index, array) { console.log(index + ‘: ‘ + val); });
// output $ node process.js one two=three four 0: node 1: /Users/node/process.js 2: one 3: two=three 4: four
process.env。返回用户设置的环境变量。
```json
// index.js
console.log(process.env.NODE_ENV) // production
// output
$ cross-env NODE_ENV=production node index
production
process.cwd()。返回当前进程的工作目录
和 dirname 不同, dirname 返回的是当前文件的所在目录
process.exit()。退出当前程序。
- 当执行exit()方法时,可以使用process.on(‘exit’, callback)作为退出程序前的清理工作。
process signal Events。当标准POSIX信号(opens new window)被触发(通常是process.kill(signal)或Ctrl+C等操作),nodejs进程可以通过监听对应信号来进行回调。
- SIGINT:interrupt,程序终止信号,通常在用户按下CTRL+C时发出,用来通知前台进程终止进程。
- SIGTERM:terminate,程序结束信号,通常用来要求程序自己正常退出。process.kill()缺省产生这个信号。
child_process(opens new window)
子程序,在node中,child_process这个模块非常重要。熟悉shell脚本的同学,可以用它的异步特性完成很多事情。
异步创建子程序有四种方式,后三种底层都是spawn实现的:
child_process.spawn(command[, args][, options])
- child_process.exec(command[, options][, callback])
- child_process.execFile(file[, args][, options][, callback])
child_process.fork(modulePath[, args][, options])
create child_process
child_process.spawn。Node.js 的父进程与衍生的子进程之间会建立 stdin、stdout 和 stderr 的管道。
- options.stdio: stdio(标准输入输出) 用来配置子进程和父进程之间的 IO 通道,可以传递一个数组或者字符串。如,[‘pipe’, ‘pipe’, ‘pipe’],分别配置:标准输入、标准输出、标准错误。如果传递字符串,则三者将被配置成一样的值。简要介绍其中三个可以取的值:
- pipe(默认):父子进程间建立 pipe 通道,可以通过 stream 的方式来操作 IO
- inherit:子进程直接使用父进程的 IO(该种情况使用较多,子进程命令中,执行的node文件里使用process对象与主文件中一致)
- ignore:不建立 pipe 通道,不能 pipe、不能监听 data 事件、IO 全被忽略 ```json const { spawn } = require(‘child_process’); var ls = spawn(‘ls’, [‘-al’],{ stdio: ‘inherit’ });
- options.stdio: stdio(标准输入输出) 用来配置子进程和父进程之间的 IO 通道,可以传递一个数组或者字符串。如,[‘pipe’, ‘pipe’, ‘pipe’],分别配置:标准输入、标准输出、标准错误。如果传递字符串,则三者将被配置成一样的值。简要介绍其中三个可以取的值:
ls.stdout.on(‘data’, function(data){ console.log(‘data from child: ‘ + data); });
ls.stderr.on(‘data’, function(data){ console.log(‘error from child: ‘ + data); });
ls.on(‘close’, function(code){ console.log(‘child exists with code: ‘ + code); });
- child_process.exec。创建一个shell,然后在shell里执行命令。执行完成后,将stdout、stderr作为参数传入回调方法。exec 比较适合用来执行 shell 命令,然后获取输出。
```json
const { exec } = require('child_process');
exec('ls -al', function(error, stdout, stderr){
if(error) {
console.error('error: ' + error);
return;
}
console.log('stdout: ' + stdout);
console.log('stderr: ' + typeof stderr);
});
- events。child_process支持以下事件:
- exit。子进程退出。注意其和close的区别,当exit触发时,其stdio流有可能还打开着,可以在此时做一些清理工作。通常情况下,child_process.kill()会触发该事件。
- close。当子进程关闭时。通常情况下,child_process.kill()也会触发该事件。
- error。当子进程不能关闭时,关闭它会报error事件。调用kill()可能会触发该事件。
- message。跟child_process.send方法有关,父子进程间通信。
- disconnect。跟child_process.disconnect方法有关。 ```json var child_process = require(‘child_process’)
var proc = child_process.spawn(‘pm2-runtime’, [‘proxy-server’, ‘—‘, ‘./dist’], { stdio: ‘inherit’ })
process.on(‘SIGTERM’, () => proc.kill(‘SIGTERM’)) process.on(‘SIGINT’, () => proc.kill(‘SIGINT’)) process.on(‘SIGBREAK’, () => proc.kill(‘SIGBREAK’)) process.on(‘SIGHUP’, () => proc.kill(‘SIGHUP’))
proc.on(‘exit’, process.exit)
<a name="NZG63"></a>
### [assert](https://lq782655835.github.io/blogs/node/node-usage-api-summary.html)
- assert(value[, message]) assert.ok()的别名
- assert.equal(actual, expected[, message]) 比较是否相等。equal是非严格模式,官方推荐使用严格模式assert.strictEqual()。
- assert.notEqual(actual, expected[, message])
- assert.ok(value[, message]) 测试 value 是否为真值。相当于 assert.equal(!!value, true, message)
- assert.fail([message]) 抛出 AssertionError,并带上提供的错误信息或默认的错误信息。
```json
assert.equal(1, '1'); // OK, 1 == '1'
assert.notEqual(1, 2); // OK
assert.ok(1); // 测试通过。
assert.ok(typeof 123 === 'string'); // // 抛出 AssertionError: false == true
assert.fail('失败'); // 抛出 AssertionError [ERR_ASSERTION]: 失败