前言:

因为以前学习Node.js并没有真正意义上的去学习它,而是粗略的学习了npm的常用命令和Node.js一些模块化的语法,因而昨天花了一天的工夫看了《Node.js开发指南》一书。通过这本书倒是让我对Node.js的意识更为全面,但因为这本书出版工夫过早,有些API曾经产生了变动或曾经被废除,而对于学习Node.js来说,外围局部又是最为重要的一环,因而我配合官网文档对这本书的第四章-Node.js外围进行了总结与梳理,因为程度无限,如有疏漏与谬误,请斧正。

注释

外围模块是Node.js的心脏,次要是有一些精简高效的库组成(这方面和Python有很大的相似之处),为Node.js提供了根底的API。次要内容包含:

Node.js外围入门(一)

全局对象
常用工具
事件机制

Node.js外围入门(二)

文件系统拜访
HTTP服务器与客户端

全局对象

全局对象我想学过JavaScript的都晓得在浏览器是window,在程序的任何中央都能够拜访到全局对象,而在Node.js中,这个全局对象换成了global,所有的全局变量(除了global自身)都是global对象的属性。而咱们在Node.js中可能间接拜访的对象通常都是global的属性,如:console,process等。

全局对象与全局变量

global最基本的作用就是作为全局变量的宿主。依照ECMAScript标准,满足以下条件的变量即为全局变量:

  • 在最外层定义的变量(在Node.js中不存在,因为Node.js的代码在模块中执行,不存在在最外层定义变量)
  • 全局对象的属性
  • 隐式定义的变量(即未定义而间接进行赋值的变量)

当咱们定义一个全局变量的时候,这个全局变量会主动成为全局变量的属性。

process

process 对象是一个全局变量,它提供以后 Node.js 过程的相干信息,以及管制以后 Node.js 过程。通常咱们在写本地命令行程序的时候,少不了和它打交道。上面是它的最罕用的成员办法:

1.process.argv

process.argv 属性返回一个数组,这个数组蕴含了启动Node.js过程时的命令行参数。第一个元素为process.execPath,第二个元素为以后执行的JavaScript文件门路,残余的元素为其余命令行参数。

例如存储一个名为argv.js的文件:

// print process.argvprocess.argv.forEach((val, index) => { console.log(`${index}: ${val}`);}); 

则命令行运行时这样的:

$ node process-args.js one two=three four0: /usr/local/bin/node1: /Users/mjr/work/node/process-args.js2: one3: two=three4: four 

2.process.stdout

process.stdout是规范输入流,通常咱们应用的console.log()输入打印字符,而process.stdout.write()函数提供了更为底层的接口。

process.stdout.write('请输出num1的值:');

3.process.stdin

process.stdin是规范输出流,初始时它是暂停的,要想从规范输出读取数据,咱们必须复原流,并手动编写流的事件响应函数。

/*1:申明变量*/var num1, num2;/*2:向屏幕输入,提示信息,要求输出num1*/process.stdout.write('请输出num1的值:');/*3:监听用户的输出*/process.stdin.on('data', function (chunk) {   if (!num1) {       num1 = Number(chunk);       /*4:向屏幕输入,提示信息,要求输出num2*/       process.stdout.write('请输出num2的值');   } else {       num2 = Number(chunk);       process.stdout.write('后果是:' + (num1 + num2));   }}); 

4.process.nextTick(callback[, ...args])

...args <any> 调用 callback时传递给它的额定参数
process.nextTick()办法将 callback 增加到"next tick 队列"。 一旦以后事件轮询队列的工作全副实现,在next tick队列中的所有callbacks会被顺次调用。
这种形式不是setTimeout(fn, 0)的别名。它更加有效率,因而别用setTimeout去代替process.nextTick。事件轮询随后的ticks 调用,会在任何I/O事件(包含定时器)之前运行。

console.log('start');process.nextTick(() => { console.log('nextTick callback');});console.log('scheduled');// start// scheduled// nextTick callback 

4.console

console 模块提供了一个简略的调试控制台,相似于 Web 浏览器提供的 JavaScript 控制台。该模块导出了两个特定的组件:

  • 一个 Console 类,蕴含 console.log() 、 console.error() 和 console.warn() 等办法,能够被用于写入到任何 Node.js 流。
  • 一个全局的 console 实例,可被用于写入到 process.stdout 和 process.stderr。 全局的 console 应用时无需调用 require('console')。(留神:全局的 console 对象的办法既不总是同步的(如浏览器中相似的 API),也不总是异步的(如其余 Node.js 流)。

比方全局下的常见的console实例:

console.log('hello,world');// hello,worldconsole.log('hello%s', 'world');// helloworldconsole.error(new Error('错误信息'));//  Error: 错误信息const name = '形容';console.warn(`正告${name}`);// 正告形容console.trace() // 向规范谬误流输入以后的调用栈 

常见的Console类:

const out = getStreamSomehow();const err = getStreamSomehow();const myConsole = new console.Console(out, err);myConsole.log('hello,world');// hello,worldmyConsole.log('hello%s', 'world');// helloworldmyConsole.error(new Error('错误信息'));// Error: 错误信息const name = '形容';myConsole.warn(`正告${name}`);//正告形容 

常用工具 util

util 模块次要用于反对 Node.js 外部 API 的需要。 大部分实用工具也可用于应用程序与模块开发者,用于补救外围JavaScript的性能的有余。它的能够这样调用:

const util = require('util');

1.util.inspect(object[, options])

util.inspect() 办法返回 object 的字符串示意,次要用于调试和谬误输入。 附加的 options 可用于扭转格式化字符串的某些方面。它至多承受一个参数objet,即要转换的参数,而option则是可选的,可选内容如下:

  • showHidden <boolean> 如果为 true,则 object 的不可枚举的符号与属性也会被包含在格式化后的后果中。 默认为 false。
  • depth <number> 指定格式化 object 时递归的次数。 这对查看大型简单对象很有用。 默认为 2。 若要有限地递归则传入 null。
  • colors <boolean> 如果为 true,则输入款式应用 ANSI 颜色代码。 默认为 false,可自定义。
  • customInspect <boolean> 如果为 false,则 object 上自定义的 inspect(depth, opts) 函数不会被调用。 默认为 true。
  • showProxy <boolean> 如果为 true,则 Proxy 对象的对象和函数会展现它们的 target 和 handler 对象。 默认为 false。
  • maxArrayLength <number> 指定格式化时数组和 TypedArray 元素能蕴含的最大数量。 默认为 100。 设为 null 则显式全副数组元素。 设为 0 或正数则不显式数组元素。
  • breakLength <number> 一个对象的键被拆分成多行的长度。 设为 Infinity 则格式化一个对象为单行。 默认为 60。

例如,查看 util 对象的所有属性:

const util = require('util');console.log(util.inspect(util, { showHidden: true, depth: null })); 

2.util.callbackify(original)

util.callbackify(original)办法将 async 异步函数(或者一个返回值为 Promise 的函数)转换成遵循 Node.js 回调格调的函数。 在回调函数中, 第一个参数 err 为 Promise rejected 的起因 (如果 Promise 状态为 resolved , err为 null ),第二个参数则是 Promise 状态为 resolved 时的返回值。例如:

const util = require('util');async function fn() { return await Promise.resolve('hello world');}const callbackFunction = util.callbackify(fn);callbackFunction((err, ret) => { if (err) throw err; console.log(ret);});// hello world 

留神:

  • 回调函数是异步执行的, 并且有异样堆栈谬误追踪. 如果回调函数抛出一个异样, 过程会触发一个 'uncaughtException' 异样, 如果没有被捕捉, 过程将会退出。
  • null 在回调函数中作为一个参数有其非凡的意义, 如果回调函数的首个参数为 Promise rejected 的起因且带有返回值, 且值能够转换成布尔值 false, 这个值会被封装在 Error 对象里, 能够通过属性 reason 获取。
function fn() { return Promise.reject(null);}const callbackFunction = util.callbackify(fn);callbackFunction((err, ret) => {   // 当Promise的rejecte是null时,它的Error与原始值都会被存储在'reason'中。 err && err.hasOwnProperty('reason') && err.reason === null;  // true}); 

事件驱动 events

events是Node.js最重要的模块,起因是Node.js自身架构就是事件式的,大多数 Node.js 外围 API 都采纳习用的异步事件驱动架构,而它提供了惟一的接口,因而堪称Node.js事件编程的及时。events 模块不仅用于用户代码与 Node.js 上层事件循环的交互,还简直被所有的模块依赖。

所有能触发事件的对象都是 EventEmitter 类的实例。 这些对象凋谢了一个 eventEmitter.on() 函数,容许将一个或多个函数绑定到会被对象触发的命名事件上。 事件名称通常是驼峰式的字符串,但也能够应用任何无效的 JavaScript 属性名。对于每个事件, EventEmitter反对若干个事件监听器。当事件发射时,注册到这个事件的事件监听器被顺次调用,事件参数作
为回调函数参数传递。

例如:

const EventEmitter = require('events');class MyEmitter extends EventEmitter {}const myEmitter = new MyEmitter();// eventEmitter.on() 办法用于注册监听器myEmitter.on('event', () => { console.log('触发了一个事件!');});// eventEmitter.emit() 办法用于触发事件myEmitter.emit('event'); 

上面让咱们来看看EventEmitter最罕用的API:

-EventEmitter.on(event, listener) 办法能够增加 listener 函数到名为 eventName 的事件的监听器数组的开端。不会查看 listener 是否已被增加。屡次调用并传入雷同的 eventName 和 listener 会导致 listener 被增加与调用屡次。
-emitter.prependListener(eventName, listener)办法能够增加 listener 函数到名为 eventName 的事件的监听器数组的结尾。 不会查看 listener 是否已被增加。 屡次调用并传入雷同的 eventName 和 listener 会导致 listener 被增加与调用屡次。
-eventEmitter.emit() 办法容许将任意参数传给监听器函数。当一个一般的监听器函数被 EventEmitter 调用时,规范的 this 关键词会被设置指向监听器所附加的 EventEmitter。

// 实例:const myEE = new EventEmitter();myEE.on('foo', () => console.log('a'));myEE.prependListener('foo', () => console.log('b'));myEE.emit('foo');// 打印://   b//   a 
  • EventEmitter.once(event, listener) 为指定事件注册一个单次监听器,即监听器最多只会触发一次,触发后立即解除该监听器。
server.once('connection', (stream) => {  console.log('首次调用!');}); 
  • EventEmitter.removeListener(event, listener) 移除指定事件的某个监听器, listener 必须是该事件曾经注册过的监听器。(留神:removeListener 最多只会从监听器数组里移除一个监听器实例。 如果任何繁多的监听器被屡次增加到指定 eventName 的监听器数组中,则必须屡次调用 removeListener 能力移除每个实例。)
const callback = (stream) => {  console.log('有连贯!');};server.on('connection', callback);// ...server.removeListener('connection', callback); 
  • EventEmitter.removeAllListeners([event]) 移除所有事件的所有监听器,如果指定 event ,则移除指定事件的所有监听器。
const callback = (stream) => {  console.log('有连贯!');};server.on('connection', callback);// ...server.removeListener('connection', callback); 

error 事件

EventEmitter 定义了一个非凡的事件 error ,它蕴含了“谬误”的语义,咱们在遇到异样的时候通常会发射 error 事件。当 error被发射时,EventEmitter规定如果没有响
应的监听器,Node.js 会把它当作异样,退出程序并打印调用栈。咱们个别要为会发射 error 事件的对象设置监听器,防止遇到谬误后整个程序解体。

var events = require('events');var emitter = new events.EventEmitter();emitter.emit('error'); 

继承EventEmitter

大多数状况下,咱们不会间接应用EventEmitter,而是在对象中继承它,包含fs,http在内的只有是反对事件响应的外围模块都是EventEmitter的子类。这样做的起因有以下两个:

  • 具备某个实体性能的对象实现事件合乎语义,事件的监听和发射应该是一个对象的办法。
  • JavaScript 的对象机制是基于原型的,反对局部多重继承,继承 EventEmitter 不会打乱对象原有的继承关系。