Node.js in Practice总结1

Node.js概述

Node.js是基于V8, 用于开发网络应用的一个平台, 它主要包含了基于TCP的异步操作和同步文件管理.

为什么要使用Node.js

Node.js使用的是非阻塞的I/O.

Node.js的主要特性

屏幕快照 2016-11-19 下午1.09.19

EventEmitter: 事件API

简单来说, 就是事件的发送接收机制. 例如在系统的某个地方, 我们发送了一个start消息, 在另外一个专门等待start信息的模块接收到这个信息后, 就开始处理事情.

Node.js中的streams, networking和file system都基于EventEmitter.

var EventEmitter = require('events').EventEmitter;

class MyEmitter extends EventEmitter {}

var myEmitter = new MyEmitter();

myEmitter.on('show', () => {
  console.log('hello world');
});

myEmitter.emit('show');

Stream: 可扩展I/O

Stream是基于EventEmitter, 主要用于处理数据流.

使用Stream可以创建一个对象来接收所连接事件的数据: data用于新数据流入, end表明没有数据流入, 而error表明错误发生.

const fs = require('fs');

var input = fs.createReadStream(__filename);

input.on('data', (chunk) => {
  if (chunk) {
    process.stdout.write(chunk);
  }
});

input.on('end', () => {
  process.stdout.write('\nend!\n');
});

input.on('error', (err) => {
  if (err) throw err;
});

使用pipe管道可简化代码:

var fs = require('fs');

var input = fs.createReadStream(__filename);
var output = fs.createWriteStream('output.txt');
input.pipe(output);

不使用流处理:

var fs = require('fs');

fs.readFile(__filename, (err, chunk) => {
  if (err) return console.error(err);
  if (chunk) process.stdout.write(chunk.toString());
});

 

FS: 文件操作

可同步或异步的读取文件.

NET: 用于创建网络客户端和服务端

基于HTTP协议, 用于操作网络.

Node.js环境

模块

当我们安装第三方模块时, 我们可以使用npm.

lgtdeMacBook-Pro:test lgt$ cnpm install express
→ express@4.14.0 › type-is@1.6.14 (09:11:00)
→ express@4.14.0 › accepts@1.3.3 › mime-types@2.1.13 (05:39:28)
lgtdeMacBook-Pro:test lgt$ vim test.js
lgtdeMacBook-Pro:test lgt$ node test.js
function
lgtdeMacBook-Pro:test lgt$ cat test.js
var express = require('express');
console.log(typeof express);

这里使用了淘宝镜像cnpm, 安装则执行:

cnpm install xxx

默认安装在当前目录的node_modules下. 如果加上 -g 参数, 则默认全局安装, 一般在/usr/local/lib/node_modules下.

使用require("xxx")来加载模块.

通过module.exports加载当个文件的单个对象, 而exports加载单个文件的多个对象.

编程讲究模块思想, 我们可以将代码分割成多个功能模块, 使用module.exports/exports进行加载.

myclass.js:

function MyClass() {}

MyClass.prototype = {
  method: function() {
    return 'Hello';
  }
};

var myClass = new MyClass();

module.exports = myClass;

module-2.js:

exports.method = function() {
    return 'Hello';
};
exports.method2 = function() {
    return 'Hello again';
};

test.js:

var myClass = require('./myclass');
var module2 = require('./module-2');

console.log(myClass.method());
console.log(module2.method());
console.log(module2.method2());

运行程序, 则输出:

lgtdeMacBook-Pro:test lgt$ node test.js
Hello
Hello
Hello again

因为存在require.cache, 所以不要担心不断的require导致文件被重复的加载. 而require.resolve会解析出当前加载模块的具体文件路径, 如果想卸载某个功能模块, 我们可以编写如下的代码:

delete require.cache(require.resolve('./myclass'));

加载一组文件情况下, 我们可以编写index.js

在group目录下有三个文件:

one.js:

module.exports = function() {
    console.log('one');
};

two.js:

module.exports = function() {
    console.log('two');
};

index.js:

module.exports = {
    one: require('./one'),
    two: require('./two')
};

test.js:

var group = require('./group');
group.one();
group.two();

运行程序, 则输出:

lgtdeMacBook-Pro:test lgt$ node test.js
one
two

在require一个目录时候, 默认会加载index.js文件.

使用__dirname/__filename来获取当前目录和文件

lgtdeMacBook-Pro:test lgt$ cat test.js
console.log('__dirname:', __dirname);
console.log('__filename:', __filename);
lgtdeMacBook-Pro:test lgt$ node test.js
__dirname: /Users/lgt/test
__filename: /Users/lgt/test/test.js

I/O

从标准输入输出流(process.stdin/process.stdout)进行数据的读写

process.stdin.resume();
process.stdin.setEncoding('utf8');

process.stdin.on('data', function(text) {
    process.stdout.write(text.toUpperCase());
});

运行程序, 则输出:

lgtdeMacBook-Pro:test lgt$ cat process.js | node process.js
PROCESS.STDIN.RESUME();
PROCESS.STDIN.SETENCODING('UTF8');

PROCESS.STDIN.ON('DATA', FUNCTION(TEXT) {
PROCESS.STDOUT.WRITE(TEXT.TOUPPERCASE());
});

这里用到了管道, process.stdin为标准输入流, process.stdout为标准输出流.

使用console.time()/console.timeEnd()来统计运行时间

console.time('read');
var fs = require('fs');
var input = fs.createReadStream(__filename);
var output = fs.createWriteStream('output.txt');
input.pipe(output);
input.on('end', () => {
  console.timeEnd('read');
});

终端输出:

leicj@leicj:~/test$ node test.js
read: 5.922ms

操作系统和命令行

使用process.arch/process.platform获取操作系统和平台信息

lgtdeMacBook-Pro:test lgt$ node test.js
process.arch: x64
process.platform: darwin

使用process.argv传递命令行参数


lgtdeMacBook-Pro:test lgt$ node test.js a b c d
process.argv: [ '/usr/local/bin/node',
'/Users/lgt/test/test.js','a','b','c','d' ]

使用process.exit(status_code)传递状态码并退出程序

使用process来接收信号

process.stdin.resume();
process.on('SIGINT', () => {
  console.log('Reloading configuration...');
});
console.log('PID:', process.pid);

运行终端:

leicj@leicj:~/test$ node test.js
PID: 7203
^CReloading configuration...
^CReloading configuration...
^CReloading configuration...
^CReloading configuration...
^CReloading configuration...
^CReloading configuration...
^CReloading configuration...

Buffers: 认识bits, bytes和encodings

改变数据编码

默认情况下, Node.js的核心功能模块都是返回buffer的.

将buffer转换为其他数据结构

使用Buffer的toString方法, 将buffer转换为默认的UTF-8.

var fs = require('fs');
fs.readFile(__filename, (err, chunk) => {
  if (err) return console.error(err);
  console.log(chunk);
  console.log(chunk.toString());
});

备注: 这里不能使用process.stdout.write, 否则输出字符串. 考虑以下代码:

> var buf = Buffer.from('hello')
undefined
> buf + ''
'hello'
> buf
<Buffer 68 65 6c 6c 6f>

如果在toString()中传递参数, 则将buffer转换为其它数据结构, 也可以通过new Buffer(str, 'xxx')将其它数据结构转换为buffer.

> var s = "hello"
undefined
> var s1 = new Buffer(s).toString('base64')
undefined
> s1
'aGVsbG8='
> new Buffer(s1, 'base64').toString()
'hello'

事件: 处理EventEmitter

基本用法

从EventEmitter中继承

EventEmitter中存在两个基本函数: on用于接收信号, 而emit用于发射信号.

var EventEmitter = require('events').EventEmitter;

class MyEmitter extends EventEmitter {}

var myEmitter = new MyEmitter();

myEmitter.on('show', () => {
  console.log('show');
});

myEmitter.on('show', () => {
  console.log('show again');
});

myEmitter.emit('show');

终端输出:

lgtdeMacBook-Pro:test lgt$ node test.js
show
show again

EventEmitter提供两个函数用于删除listener, emitter.removeListener用于删除特定的的事件, 而emitter.removeAllListeners用于删除所有的事件.

而对于emitter.removeListener来说, 需要提供第二个参数: 事件中执行的函数名.

var EventEmitter = require('events').EventEmitter;

class MyEmitter extends EventEmitter {}

var myEmitter = new MyEmitter();

function f1() {
  console.log('f1');
}
function f2() {
  console.log('f2');
}

myEmitter.on('show', f1);
myEmitter.on('show', f2);

myEmitter.removeListener('show', f1);

myEmitter.emit('show');

运行程序, 则输出:

lgtdeMacBook-Pro:test lgt$ node test.js
f2

错误处理

正常情况下, 如果程序发生异常, 则会将异常信息打印在终端, 并且终止程序.

但我们可以捕获异常信息:

var EventEmitter = require('events').EventEmitter;

class MyEmitter extends EventEmitter {}

var myEmitter = new MyEmitter();

myEmitter.on('show', () => {
  myEmitter.emit('error', 'unable to show');
});

myEmitter.on('error', (err) => {
  console.error('Error:', err);
});

myEmitter.emit('show');

运行程序, 输出:

lgtdeMacBook-Pro:test lgt$ node test.js
Error: unable to show

如果存在多个EventEmitter对象, 甚至存在嵌套的对象, 每个对象都会emit一个错误信息, 则最好使用domain来处理异常.

var d = require('domain').create();
  d.on('error', (er) => {
    console.log('error, but oh well', er.message);
  });
  d.run(() => {
    require('http').createServer((req, res) => {
    handleRequest(req, res);
  }).listen(PORT);
});

这时候, 如果运行程序, 则提示如下的错误:

error, but oh well PORT is not defined

高级主题

假设存在一种情况, 我们需要监听一个listener加入到EventEmitter, 或者查看所有的listeners.

EventEmitter提供一个特殊的事件: newListener

var EventEmitter = require('events').EventEmitter;

class MyEmitter extends EventEmitter {}

var myEmitter = new MyEmitter();

myEmitter.on('newListener', (name, listener) => {
  console.log('Event name added:', name);
});

myEmitter.on('a listener', () => {});

运行程序后输出:

Event name added: a listener

我们可以使用listeners获取所有的监听事件(针对同一个name):

var EventEmitter = require('events').EventEmitter;

class MyEmitter extends EventEmitter {}

var myEmitter = new MyEmitter();

myEmitter.on('a listener', () => {});
myEmitter.on('a listener', () => {});

// 2
console.log(myEmitter.listeners('a listener').length);

在一个大型的系统中, 例如不同的功能模块如果要进行通信, 我们也可以通过EventEmitter来实现:

var express = require('express');
var app = express();

app.on('hello-alert', function() {
  console.warn('warning!');
});

app.get('/', function(req, res) {
  res.app.emit('hello-alert');
  res.send('hello world');
});

app.listen(3000);

 

转载于:https://my.oschina.net/voler/blog/807513

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
英文原版,无水印,数字版,有目录。 Node.js in Practice 1st Edition Summary Node.js in Practice is a collection of fully tested examples that offer solutions to the common and not-so-common issues you face when you roll out Node. You'll dig into important topics like the ins and outs of event-based programming, how and why to use closures, how to structure applications to take advantage of end-to-end JavaScript apps, and more. Purchase of the print book includes a free eBook in PDF, Kindle, and ePub formats from Manning Publications. About the Book You've decided to use Node.js for your next project and you need the skills to implement Node in production. It would be great to have Node experts Alex Young and Marc Harter at your side to help you tackle those day-to-day challenges. With this book, you can! Node.js in Practice is a collection of 115 thoroughly tested examples and instantly useful techniques guaranteed to make any Node application go more smoothly. Following a common-sense Problem/Solution format, these experience-fueled techniques cover important topics like event-based programming, streams, integrating external applications, and deployment. The abundantly annotated code makes the examples easy to follow, and techniques are organized into logical clusters, so it's a snap to find what you're looking for. Written for readers who have a practical knowledge of JavaScript and the basics of Node.js. What's Inside Common usage examples, from basic to advanced Designing and writing modules Testing and debugging Node apps Integrating Node into existing systems About the Authors Alex Young is a seasoned JavaScript developer who blogs regularly at DailyJS. Marc Harter works daily on large-scale projects including high-availability real-time applications, streaming interfaces, and other data-intensive systems. Table of Contents PART 1 NODE FUNDAMENTALS Getting started Globals: Node's environment Buffers: Working with bits, bytes, and encodings Events: Mastering EventEmitter and beyond Streams: Node's most powerful and misunderstood feature File system: Synchronous and asynchronous approaches Networking: Node's true "Hello, World" Child processes: Integrating external applications with Node PART 2 REAL-WORLD RECIPES The Web: Build leaner and meaner web applications Tests: The key to confident code Debugging: Designing for introspection and resolving issues Node in production: Deploying applications safely PART 3 WRITING MODULES Writing modules: Mastering what Node is all about
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值