本文共 7567 字,大约阅读时间需要 25 分钟。
前言:
因为以前学习Node.js并没有真正意义上的去学习它,而是粗略的学习了npm的常用命令和Node.js一些模块化的语法,因此昨天花了一天的时间看了《Node.js开发指南》一书。通过这本书倒是让我对Node.js的认识更为全面,但由于这本书出版时间过早,有些API已经发生了变化或已经被废弃,而对于学习Node.js来说,核心部分又是最为重要的一环,因此我配合官方文档对这本书的第四章-Node.js核心进行了总结与梳理,由于水平有限,如有疏漏与错误,请指正。
核心模块是Node.js的心脏,主要是有一些精简高效的库组成(这方面和Python有很大的相似之处),为Node.js提供了基础的API。主要内容包括:
Node.js核心入门(一)
Node.js核心入门(二)
全局对象我想学过JavaScript的都知道在浏览器是window,在程序的任何地方都可以访问到全局对象,而在Node.js中,这个全局对象换成了global,所有的全局变量(除了global本身)都是global对象的属性。而我们在Node.js中能够直接访问的对象通常都是global的属性,如:console,process等。
global最根本的作用就是作为全局变量的宿主。按照ECMAScript规范,满足以下条件的变量即为全局变量:
当我们定义一个全局变量的时候,这个全局变量会自动成为全局变量的属性。
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
console 模块提供了一个简单的调试控制台,类似于 Web 浏览器提供的 JavaScript 控制台。该模块导出了两个特定的组件:
比如全局下的常见的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 模块主要用于支持 Node.js 内部 API 的需求。 大部分实用工具也可用于应用程序与模块开发者,用于弥补核心JavaScript的功能的不足。它的可以这样调用:
const util = require('util');
util.inspect() 方法返回 object 的字符串表示,主要用于调试和错误输出。 附加的 options 可用于改变格式化字符串的某些方面。它至少接受一个参数objet,即要转换的参数,而option则是可选的,可选内容如下:
例如,查看 util 对象的所有属性:
const util = require('util');console.log(util.inspect(util, { showHidden: true, depth: null }));
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
注意:
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是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:
// 实例:const myEE = new EventEmitter();myEE.on('foo', () => console.log('a'));myEE.prependListener('foo', () => console.log('b'));myEE.emit('foo');// 打印:// b// a
server.once('connection', (stream) => { console.log('首次调用!');});
const callback = (stream) => { console.log('有连接!');};server.on('connection', callback);// ...server.removeListener('connection', callback);
const callback = (stream) => { console.log('有连接!');};server.on('connection', callback);// ...server.removeListener('connection', callback);
EventEmitter 定义了一个特殊的事件 error ,它包含了“错误”的语义,我们在遇到异常的时候通常会发射 error 事件。当 error被发射时,EventEmitter规定如果没有响
应的监听器,Node.js 会把它当作异常,退出程序并打印调用栈。我们一般要为会发射 error 事件的对象设置监听器,避免遇到错误后整个程序崩溃。var events = require('events');var emitter = new events.EventEmitter();emitter.emit('error');
大多数情况下,我们不会直接使用EventEmitter,而是在对象中继承它,包括fs,http在内的只要是支持事件响应的核心模块都是EventEmitter的子类。这样做的原因有以下两个:
作者:srtian 链接:https://www.jianshu.com/p/9d04d5ea783d 來源:简书 简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。