编程语言
首页 > 编程语言> > Node.js核心入门

Node.js核心入门

作者:互联网

前言:

因为以前学习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规范,满足以下条件的变量即为全局变量:

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

process

process 对象是一个全局变量,它提供当前 Node.js 进程的相关信息,以及控制当前 Node.js 进程。通常我们在写本地命令行程序的时候,少不了和它打交道。下面是它的最常用的成员方法:

1.process.argv

process.argv 属性返回一个数组,这个数组包含了启动Node.js进程时的命令行参数。第一个元素为process.execPath,第二个元素为当前执行的JavaScript文件路径,剩余的元素为其他命令行参数。

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

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

则命令行运行时这样的:

$ node process-args.js one two=three four

0: /usr/local/bin/node
1: /Users/mjr/work/node/process-args.js
2: one
3: two=three
4: 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 调用 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

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

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

console.log('hello,world');
// hello,world
console.log('hello%s', 'world');
// helloworld
console.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,world
myConsole.log('hello%s', 'world');
// helloworld
myConsole.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则是可选的,可选内容如下:

例如,查看 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

注意:

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

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的子类。这样做的原因有以下两个:

标签:Node,console,入门,process,EventEmitter,js,监听器
来源: https://blog.csdn.net/Kepler_II/article/details/115055737