了不起的Node.js
呀在北京的第四本书是 node。之前草草过了一遍《node高级程序设计》发现没消化下去,又要重新开始了。买了转换口还是没得愉快地上网啊
安装
- REPL模式( Read-Evaluate-Print-Loop,输入 -求值 -输出 -循环),即交互式命令行解析器
Javascript概述
- V8中要获取对象上的自有属性,可以通过
Object.keys(obj)
- 建议为函数命名,有利于调试
__proto__
实现继承
阻塞与非阻塞IO
- 事件轮询,Node 会先注册事件,随后不停地询问内核这些时间是否已经分发。当事件分发时,对应的回调函数会被触发,然后继续执行下去
- 错误追踪,与执行上下文相关
Node中的Javascript
- global 对象,任何 global 对象上的属性都可以被全局访问到
- process 对象,所有全局执行上下文中的内容都在 process 对象中
- 绝对模块是指 Node 通过在其内部的 node_module 查找到的模块,或者 node 内置的模块;相对模块将
require
指向一个相对工作目录中的文件 EventEmmiter
实现事件的监听和分发
Node重要的API
CLI
// 包含了所有 Node 程序运行时的参数值// [node, '文件路径', '程序运行参数值']process.argv// 文件在文件系统中的目录__dirname// 工作目录process.cwd()// 改变工作目录process.chdir('/home')// 访问 shell 环境的变量process.env// 将参数添加进 process.env$ NODE_ENV="production" node// 退出process.exit(1)// NODE 程序通过在 process 对象上,// 以事件分发的方式发送信号process.on('SIGKILL', function() {// 信号已收到});// ANSI 转义码,控制格式、颜色及其他输出选项// \033 表示转移序列开始// [ 表示开始颜色设置// 90 表示前景色为亮灰色// m 表示颜色设置结束// 39 表示将颜色设置回去console.log('\033[90m' + 'hello' + '\033[39m');fs Stream
var stream = fs.createReadStream('a.txt');stream.on('data', function() {// 处理部分内容});stream.on('end', function() {// 文件读取完毕});
fs 监视
var file = 'a.txt';fs.watchFile(file, function() {console.log('- ' + file + ' changed');});// 通过 watch 监视目录输入输出
process.stdout.write('show me something: \n');process.stdin.setEncoding('utf8');process.stdin.resume();process.stdin.on('data', function(data) {process.stdout.write('entry: ' + data + '\n');});
TCP
创建基本的 TCP 服务器
createServer
回调函数会接收一个对象,传递net.Stream
,通常可读写
listen
将服务器绑定在某个端口上var net = require('net');var server = net.createServer(function(conn) {// handle connectionconsole.log('\033[90m new connection\033[39m');});server.listen(3000, function() {console.log('\033[96m server listening on *:3000\033[39m');});telnet 127.0.0.1 3000
创建基本的 TCP 客户端
var net = require('net');var client = net.connect('3000', '127.0.0.1');client.on('connect', function() {console.log('done');});
HTTP
头信息
- Content-Type:发送内容的类型(text, HTML, XML, JSON, PNG, JPEG)
- Transfer-Encoding:默认值是 chunked,主要原因是 Node 天生的异步机制
连接
HTTP 服务器是更高层的 API,提供了控制和 HTTP 协议相关的功能
// 简单 http 服务器require('http').createServer(function(req, res) {res.writeHead(200, { 'Content-Type': 'text/html'});res.write('<h1>hello</h1>');res.end(req.url + req.method);}).listen(3000);// 简单 HTTP 客户端require('http').request({host: '127.0.0.1',port: 3000,url: '/',method: 'GET'}, function (res) {var body = '';res.on('data', function(chunk) {body += chunk;});res.on('end', function() {console.log(body);});}).end();// 客户端请求数据var qs = require('querystring');require('http').request({host: '127.0.0.1',port: 3000,url: '/',method: 'POST' // 此处为 GET 时, Error: socket hang up}, function (res) {var body = '';res.on('data', function(chunk) {body += chunk;});res.on('end', function() {console.log(body);});res.setEncoding('utf8');}).end( qs.stringify({name: "lance"}) );// 表单数据require('http').createServer(function(req, res) {var body = '';req.on('data', function(chunk) {body += chunk;});req.on('end', function() {res.writeHead(200, { 'Content-type': 'text/html' });res.end(req.headers['content-type'] + '<br>' + body);});}).listen(3000);
Web开发
Connect
Connect 是一个基于 HTTP 服务器的工具集,它提供了一种新的组织代码的方式来与请求、响应对象进行交互,称为中间件( middleware )。简单来说,中间件由函数组成,除了处理
req
和res
对象之外,还接收一个next
函数作为流控制static 中间件
Connect 允许将中间件挂载到 URL 上。static 允许将任意一个 URL 匹配到文件系统中任意一个目录// 挂载server.use('/my-iamges', conn.static('/path/to/ images'));// 设置 maxAgeserver.use('/js', conn.static('/path/to/js', {maxAge: 1000}));query 中间件
server.use(connect.query);server.use(function(req, res) {//req.query.page = 5;});logger 中间件
提供四种日志格式,default、dev、short、tinyserver.use(connect.logger('dev'));var connect = require('connect');connect.createServer(connect.logger('dev'),function(req, res) {res.writeHead(200);res.end('hello');}).listen(3000);body parse 中间件
body parse 会自动检测 Content-Type 的值,也可以用于文件上传server.use(connect.bodyParser());server.use(function(req, res) {// req.body.myinput});cookie
浏览器发送 cookie 数据时,会将其写到 Cookie 头信息中。其数据格式和 URL 中的查询字符串类似。server.use(connect.cookieParser());server.use(function(req, res) {// req.cookies.sercret1 = 'value1';});session
var connect = require('connect');connect.createServer(connect.logger('dev'),connect.bodyParser(),connect.cookieParser(),connect.session({ secret: 'my secret app'}),function(req, res, next) {if(req.session.login_in) {res.end('hello');} else {next();}},function(req, res) {req.session.login_in = true;res.end('login');}).listen(3000);
Express
WebSocket
包括浏览器实现的 WebSocket API,和服务器端实现的 WebSocket 协议。前者被 W3C 标准化,后者被 IETF 标准化为 RFC 6455
客户端实现
|
服务器端实现
|
关于 WebSocket 的问题
- 关闭不意味着断开连接
- JSON 编码和解码
- 重连
- 广播
- 浏览器支持
通过 socket.io 解决
Socket.IO
客户端实现
|
服务器端实现
|
测试
简单测试
|
expect.js
|
Mocha
|
BDD风格
行为驱动开发中,定义系统的行为是主要工作,而对系统行为的描述则变成了测试标准。上面的测试代码都属于BDD风格
TDD风格
测试驱动开发,与 BDD 类似,但组织方式是使用测试集(suite)和测试(test)。每个测试集都有 setup
和 teardown
函数,这些方法会在测试集中的测试执行前执行,它们的作用是为了避免代码重复以及最大限度使得测试之间相互独立
|
export风格
export 风格使用 node 模块系统来输出测试,每一个 export 的键都表示测试集,嵌套的测试集可以用子对象来表示
|