Node.js the Right Way总结1

原创
2017/01/12 17:14
阅读数 227

Node.js应用如何工作

Node.js基于事件循环(event loop), 当事件发生时候分发其操作.

const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}

const myEmitter = new MyEmitter();

myEmitter.on('event', () => {
  console.log('this is an event occur!');
});

myEmitter.emit('event');

1. myEmitter使用on注册了信号event, 并提供了处理函数.

2. emit触发了信号event, 导致处理函数执行.

Node.js使用单线程, 但使用了非阻塞技术: 使用回调函数来等待对应操作完成后执行.

 

Node.js事件循环编程

观察文件是否改变

const fs = require('fs');

fs.watch(__dirname, function(eventType, filename) {
  console.log(`eventType:${eventType}; filename:${filename}`);
});

创建子进程

const spawn = require('child_process').spawn;
const ls = spawn('ls', ['-lh', '/usr']);

ls.stdout.on('data', (data) => {
  console.log(`stdout: ${data}`);
});

ls.stderr.on('data', (data) => {
  console.log(`stderr: ${data}`);
});

ls.on('close', (code) => {
  console.log(`child process exited with code ${code}`);
});

异步读写文件

const fs = require('fs');
fs.writeFile('.temp', 'hello world', function(err) {
  if (err) throw err;
  fs.readFile('.temp', function(err, data) {
    if (err) throw err;
    console.log(data.toString());
  });
});

创建读写流

const fs = require('fs');
const inputStream = fs.createReadStream(__filename);
const outputStream = fs.createWriteStream('.temp');

inputStream.pipe(outputStream);

当然, 也可以使用on('data')来获取数据流:

const fs = require('fs');
const inputStream = fs.createReadStream(__filename);
const outputStream = fs.createWriteStream('.temp');

inputStream.on('data', function(chunk) {
  if (chunk) outputStream.write(chunk.toString());
});

 

Sockets网络编程

const net = require('net');
const server = net.createServer((c) => {
  console.log('client connected');
  c.on('end', () => {
    console.log('client disconnected');
  });
  c.write('hello\r\n');
  c.pipe(c);
});

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

server.listen(8124, () => {
  console.log('server bound');
});

1. 使用net模块创建网络服务, 监听(listen)8124端口.

2. 使用write函数将hello写到客户端.

3. c.pipe(c)的意思是: c为一个duplex stream, 它即可读取, 也可写入. 所以它执行将数据写入到自身的操作.

终端1输出:

leicj@leicj:~/test$ node test.js
server bound
client connected

终端2输出:

leicj@leicj:~/test$ telnet localhost 8124
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
hello
hello world
hello world

我们可以创建一个connect来链接服务器:

const net = require('net');
const client = net.connect({port: 8124}, () => {
  console.log('connected to server!');
  client.write('world!\r\n');
});
client.on('data', (data) => {
  console.log(data.toString());
});
client.on('end', () => {
  console.log('disconnected from server');
});

终端1:

leicj@leicj:~/test$ node test.js
server bound
client connected

终端2:

leicj@leicj:~/test$ node connect.js 
connected to server!
hello

world!

 

Express的优势

使用http编写一个简单的服务模块:

const http = require('http'),
  server = http.createServer((req, res) => {
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('Hello World\n');
  });

server.listen(3000, () => {
  console.log('ready captain!');
});

这是简单的TCP服务, 创建服务, 监听3000端口, 返回Hello World. 但使用http会忽略以下基本的额外工作:

1. 基于URL的路由机制.

2. 通过cookies管理sessions.

3. 解析收到的请求数据.

4. 拒绝不合理的请求.

一个使用express(^4.14.0)的例子:

const express = require('express'),
  morgan = require('morgan'),
  app = express();

app.use(morgan('combined'));

app.get('/api/:name', (req, res) => {
  res.json(200, {'hello': req.params.name});
});
app.listen(3000, () => {
  console.log('ready captain.');
});

1. 在express第四版本中, 一些中间件被替换, 例如使用morgan替换了logger.

2. '/api/:name'的语法的含义是: 任何name的值, 会保存在req.params.name中.

3. req代表客户端返回给服务端的请求, 而res代表服务端返回给客户端的请求. 200代表正确的状态码.

备注: 4, 5, 6, 7章节中, 第四章环境搭建失败, 第五章中数据库的数据下载失败, 第六章的expres用到了第五章的数据, 第七章也是.

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部