总结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值

    1. path(opens new window)
    2. __filename。全局值,当前文件绝对路径
    3. __dirname。全局值,当前文件夹绝对路径。等效于path.resolve(__filename, '..')
    4. path.join([...paths])。相当于把所传入的任意多的参数 按照顺序 进行命令行般的推进
    5. path.resolve([...paths])。以当前文件的路径为起点,返回绝对路径。可以理解为每次都是新建cd命令
    6. path.dirname(path)。返回指定路径所在文件夹的路径
    7. path.basename(path)。返回指定Path路径所在文件的名字
    8. path.extname(path)。获取指定字符串或者文件路径名字的后缀名,带.比如.txt
    9. 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‘ } /
  1. - url.format(urlObject)。把url对象解析为字符串
  2. - url.resolve(from, to)。以一种 Web 浏览器解析超链接的方式, 基于一个基础 URL,对目标 URL进行解析。查看其源码实现:
  3. ```json
  4. Url.prototype.resolve = function(relative) {
  5. return this.resolveObject(urlParse(relative, false, true)).format();
  6. };

querystring

  • querystring.parse。一个URL查询字符串 str 解析成一个键值对的集合。 ```json const querystring = require(‘querystring’) let query = querystring.parse(‘type=123’) console.log(query) // { type: ‘123’ }
  1. - querystring.stringify。遍历给定的 obj 对象的自身属性,生成 URL 查询字符串。
  2. <a name="jqRU1"></a>
  3. ## [Stream](https://lq782655835.github.io/blogs/node/node-usage-api-summary.html)
  4. **Node中很多数据结构都继承自Stream**。Stream在文件系统和http请求中,有非常大的作用。
  5. - 对于文件处理,小文件对于buffer数据结构能很好的解决,直接将文件所有数据加载到内存中;但对于大文件,buffer这种方式不可取,容易打爆内存。最好的方式是像流水一样,将读取的数据实时流入到写入的文件,直到数据全部读完并写入好对应目标文件。举个例子,就像两个水池,待读取的文件是一个装满水的池子,写入的空文件是一个等待蓄满水的空池子。通过Stream API的方式,将两个池子嫁接起来,使得满水的池子可以持续注水到空池子中。而且Stream继承自EmitEvents,过程中会有许多回调事件发出,供开发人员自定义内容。
  6. - 对于http请求处理,最常见的就是通过流去写入内容。
  7. 以下对象继承了可读流:
  8. - **HTTP responses, on the client**
  9. - **HTTP requests, on the server**
  10. - **fs read streams**
  11. - **child process stdout and stderr**
  12. - **process.stdin**
  13. - zlib streams
  14. - crypto streams
  15. - TCP sockets
  16. <a name="ljAUn"></a>
  17. ### **<br />Stream类**
  18. - stream.Writable
  19. - **write()** 写入数据到流
  20. - **end()** 表明已没有数据要被写入
  21. - Events
  22. - **drain**。 每个数据块写入成功后回调事件,可能多次触发。
  23. - pipe。当readableStream.pipe()调用时回调事件
  24. - finish writeableStream.end()调用并数据读完后回调事件。
  25. - close
  26. - error
  27. - stream.Readable
  28. - pipe(destination:stream.Writable, options) 把可读数据流入可写流中
  29. - pause() 流暂停。使读取流暂停emit 'data'事件
  30. - resume() 流重启。重新开始emit 'data'事件
  31. - unpipe()
  32. - Events
  33. - **data**。每次读取完一段数据块回调事件,可能多次触发。
  34. - readable。数据读取可用时回调事件。
  35. - **end**。 数据全部读取完成回调事件。
  36. - close
  37. - error
  38. - stream.Duplex
  39. - stream.Transform
  40. 以下举一个完整例子:
  41. ```json
  42. const fs = require('fs')
  43. let readStream = fs.createReadStream('./node/snapshot/test1.png')
  44. let writeStream = fs.createWriteStream('./node/snapshot/test1-copy.png')
  45. readStream
  46. .on('data', (chunk) => {
  47. // 当读取较大文件时,写入流的速度可能没有读入的速度快
  48. // 所以这里做了一个处理,没写完暂停读入流
  49. if (writeStream.write(chunk) === false)
  50. readStream.pause()
  51. })
  52. .on('end', () => writeStream.end())
  53. // 这里配合上面pause,写完了继续读入流
  54. writeStream.on('drain', () => readStream.resume())
  55. // 以上换成管道的方式,只需一行代码: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
  • 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
    • 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创建的

  1. // Node作为客户端发送请求
  2. const postData = querystring.stringify({
  3. 'msg': 'Hello World!'
  4. });
  5. const options = {
  6. hostname: 'www.google.com',
  7. port: 80,
  8. path: '/upload',
  9. method: 'POST',
  10. headers: {
  11. 'Content-Type': 'application/x-www-form-urlencoded',
  12. 'Content-Length': Buffer.byteLength(postData)
  13. }
  14. };
  15. const req = http.request(options, (res) => {
  16. // 响应值res作为从目标接口中获取到的值,是个readable.Stream
  17. res.setEncoding('utf8');
  18. res.on('data', (chunk) => console.log(`BODY: ${chunk}`));
  19. res.on('end', () => console.log('No more data in response.'));
  20. });
  21. req.on('error', (e) => {
  22. console.error(`problem with request: ${e.message}`);
  23. });
  24. // req作为客户端请求,是个writeable.Stream
  25. req.write(postData); // 带上参数
  26. req.end(); // 结束写入,开始发送请求。如果是http.get() API会自动带req.end()
  1. // Node作为服务端,res(response)参数继承的是writeable.Stream
  2. const http = require('http')
  3. http.createServer((req, res) => {
  4. res.write('hello world')
  5. res.end()
  6. }).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

  1. <a name="bMpiL"></a>
  2. ## [File System(opens new window)](https://nodejs.org/dist/latest-v11.x/docs/api/fs.html)
  3. - file文件操作
  4. - **readFile(path[, options], callback)**
  5. - 没有指定 encoding,则返回原始的 buffer
  6. - **writeFile(file, data[, options], callback)**
  7. - 如果文件已存在,则覆盖文件。
  8. - data支持 string/Buffer/TypedArray/DataView
  9. - data 是一个 buffer,则忽略 encoding
  10. - copyFile(src, dest[, flags], callback)
  11. - rename(oldPath, newPath, callback)。文件重命名
  12. - write(fd, string[, positinon[, encoding]], callback)。将 string 写入到 fd 指定的文件写文件
  13. - exists(url, callback(boolean))Deprecated。查询是否存在,一般用在单纯检查文件而不去操作(open/readFile/writeFile等操作文件不成立时会回调err)文件时。推荐使用fs.stat() or fs.access() 代替该方法。
  14. - **stat(path[, options],callback(err, stat))**。查询文件/目录信息
  15. - stat.isFile 是否一个普通文件
  16. - stat.isDirectory 是否一个目录
  17. - stat.ctime 最后一次修改文件的时间
  18. - createReadStream(path[, options])。 指定路径读取,获得Readable Stream。
  19. - createWriteStream(path[, options])。创建空的写入流到目标路径,获得Writeable Stream。
  20. - dir目录操作
  21. - **readdir(path[, options], callback)**。读目录,获取目录下的所有文件和文件夹名称。
  22. - rmdir(path, callback)。移除目录
  23. 文件操作的path参数,绝对路径和相对路径都支持(相对路径基于process.cwd())。
  24. ```json
  25. const fs = require('fs')
  26. const path = require('path')
  27. let dir = './node/snapshot'
  28. fs.readFile(path.join(dir, 'test1.png'), (err, data) => {
  29. console.log(Buffer.isBuffer(data)) // true
  30. fs.writeFile(path.join(dir, 'test1_copy.png'), data, (error) => console.log(error)
  31. })

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

  1. process.env。返回用户设置的环境变量。
  2. ```json
  3. // index.js
  4. console.log(process.env.NODE_ENV) // production
  5. // output
  6. $ cross-env NODE_ENV=production node index
  7. 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’ });

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); });

  1. - child_process.exec。创建一个shell,然后在shell里执行命令。执行完成后,将stdoutstderr作为参数传入回调方法。exec 比较适合用来执行 shell 命令,然后获取输出。
  2. ```json
  3. const { exec } = require('child_process');
  4. exec('ls -al', function(error, stdout, stderr){
  5. if(error) {
  6. console.error('error: ' + error);
  7. return;
  8. }
  9. console.log('stdout: ' + stdout);
  10. console.log('stderr: ' + typeof stderr);
  11. });
  • 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)

  1. <a name="NZG63"></a>
  2. ### [assert](https://lq782655835.github.io/blogs/node/node-usage-api-summary.html)
  3. - assert(value[, message]) assert.ok()的别名
  4. - assert.equal(actual, expected[, message]) 比较是否相等。equal是非严格模式,官方推荐使用严格模式assert.strictEqual()。
  5. - assert.notEqual(actual, expected[, message])
  6. - assert.ok(value[, message]) 测试 value 是否为真值。相当于 assert.equal(!!value, true, message)
  7. - assert.fail([message]) 抛出 AssertionError,并带上提供的错误信息或默认的错误信息。
  8. ```json
  9. assert.equal(1, '1'); // OK, 1 == '1'
  10. assert.notEqual(1, 2); // OK
  11. assert.ok(1); // 测试通过。
  12. assert.ok(typeof 123 === 'string'); // // 抛出 AssertionError: false == true
  13. assert.fail('失败'); // 抛出 AssertionError [ERR_ASSERTION]: 失败