Outline
1 概述和安装
- 1.1 安装Node
- 1.2 Node简介
2 Node核心API基础
- 2.1 加载模块
- 2.2 应用缓冲区处理、编码和解码二进制数据
- 2.3 使用时间发射器模式简化事件绑定
- 2.4 使用定时器制定函数执行计划
1 概述和安装
1.1 安装Node
参见Ubuntu 14.04下搭建Node.js的开发环境或其他类似文章。
npm: Node包管理器
两种主要的工作模式:全局模式、本地模式
本地模式:安装到当前目录下node_modules目录中。
常用命令:
npm install [-g] <package name>
npm install <package name>@<version specification>
npm install sax@0.2.5
npm install sax@"<0.3"
npm install sax@">=0.1.0 <0.3.1"
npm uninstall <package name>
npm update [-g] <package name>
用pacakge.json定义依赖关系
// MYAPP/package.json
{
"name":"MyApp",
"version":"1.0.1",
"dependencies":{
"sax":"0.3.x",
"nano":"*"
}
}
1.2 Node简介
事件驱动编程风格
一种编程风格,程序的执行流程取决于事件。事件由事件处理程序或者事件回调函数处理。
事件驱动编程风格中一个重要的概念:事件循环。事件循环:处于不断循环的一个结构,负责处理事件检测和事件触发处理。
在每一轮事件循环中,需要检测发生了什么事情,依据发生的事件决定调用哪个事件处理程序/事件回调函数。
闭包
本质:函数作为一等公民(first class citizen)
特性:可以记住其自身被声明的作用域(父上下文)中的变量,即使运行时父上下文已不复存在。
2 Node核心API基础
2.1 加载模块
Node.js实现了CommonJS模块标准,为每个模块赋予一个上下文,将模块隔离开来。
//1 加载核心模块
var http = require("http");
//2 加载文件模块
var myModule = require("./myModule");
// myModule.js
function doSomething(){
console.log("do something");
}
module.exports = doSomething;
//3 加载文件夹模块
var myModule = require("./myModule");
//3.1 myModule文件夹下存在package.json
{
"name":"myModule",
"main":"./lib/myModule.js" //入口点
}
//3.2 myModule文件夹下不存在pakcage.json,存在index.js
// 则index.js作为入口点
//4 从node_modules文件夹中加载
var myModule = require("myModule.js")
//CAUTION: 会首先尝试加载./node_modules/myModule.js,不存在则在上一级文件夹中查找,直到根文件
注意项:模块只会被加载一次,在首次加载时被缓存,无运行时切换机制。处理模块加载时副作用时需要特别注意。
2.2 应用缓冲区处理、编码和解码二进制数据
/**
demonstration of Buffer usage
*/
var buf1 = new Buffer("Hello World");
console.log(buf1.toString());
// convet to base64
console.log(buf1.toString("base64"));
//second parameter's candidate value: ascii, utf8, base64
var buf2 = new Buffer("SGVsbG8gV29ybGQ=", "base64");
console.log(buf2.toString("base64"));
console.log(buf1.toString());
// CAUTION: not initialized, i.e. all zero
var buf3 = new Buffer(1024);
console.log(buf3.toString());
console.log(buf3.length);
// content getter/setter
console.log(buf1[1]);// e: 101
buf1[99] = 101;// not changed
console.log(buf1.toString());
// slice: share the underling data structure
var buffer = new Buffer("What is ration is real, and what is real is rational.");
var partOfBuffer = buffer.slice(0, 15);
console.log(partOfBuffer.toString());
partOfBuffer[0] = 119;// w: 119
console.log(buffer.toString());
console.log(partOfBuffer.toString());
// copy: different underling data structure
var content = "What is ration is real, and what is real is rational.";
var buffer1 = new Buffer(content);
var targetLength = 11;
var buffer2 = new Buffer(targetLength);
var targetStart = 0;
var sourceStart = 1;
var sourceEnd = 12;// sourceStart + targetLength
buffer1.copy(buffer2, targetStart, sourceStart, sourceEnd);
console.log(buffer2.toString());
2.3 使用时间发射器模式简化事件绑定
CPS: 连续传递风格(continuation passing style)
在连续传递风格中,每个函数在执行完毕后,都会调用一个回调函数,使得程序能够继续运行。
sample:
/**
demonstration of CPS(continuation passing style)
*/
// read password
var fs = require("fs"); // see 3.1 查询和读写文件
fs.readFile("/etc/passwd", function(err, fileContent){
if(err){
throw err;
}
console.log("file content: ", fileContent.toString());
});
事件发射器模式(event emitter pattern)
应对问题:函数执行过程中出现多个事件、或者某一事件多次出现,需要执行相应的事件处理器和以可编程的方式“记录”事件和事件处理器之间的对应关系。
事件发射器模式的两个对象
- 事件发射器(event emitter):可以发射事件的对象
- 事件监听器(event listener):绑定到事件发射器上的代码,负责监听特定类型的事件
API
/**
demonstration of event emitter API, including:
- addListener/on
- once
- removetListener
- removeAllListeners,
and anyone object implemented event emitter pattern has all these methods
*/
//文件流,see 3.3 读写数据流
// read stream is an object implemented event emitter pattern
var fs = require("fs");
var path = "event_emitter_api.js";// current file
var readStream = fs.createReadStream(path);
// 1 addListener
function receiveData(data){
console.log("receiveData: got data from file read stream: %s", data.toString().substring(0,10));
}
//readStream.addListener("data", receiveData);
// or use on()
readStream.on("data", receiveData);
// 2 binding more than one event listeners
function receiveData2(data){
console.log("receiveData2: got data from file read stream: %s", data.toString().substring(0,10));
}
readStream.on("data", receiveData2);
// 3 remove event listeners
function receiveData3(data){
console.log("receiveData3: got data from file read stream: %s", data.toString().substring(0,10));
}
readStream.on("data", receiveData3);
readStream.removeListener("data", receiveData3);
// 4 once: one time shot event handler
readStream.once("data", receiveData3);
// 5 removeAllListeners
readStream.removeAllListeners("data");
自定义事件发射器
/**
demonstration of customed event emitter
*/
var util = require("util");
var EventEmitter = require("events").EventEmitter;
var MyEventEmitter = function(){
}
// construct a prototype chain, so MyEventEmitter can use prototype method of the EventEmitter
util.inherits(MyEventEmitter, EventEmitter);
MyEventEmitter.prototype.someMethod = function(){
this.emit("my event", "argument1", "argument2");
}
// usage
var myEventEmitter = new MyEventEmitter();
myEventEmitter.on("my event", function(arg1, arg2){
console.log("got a event with parameters: %s, %s", arg1, arg2);
});
// emit the event every second
function main(myEventEmitter){
setInterval(function(){
myEventEmitter.someMethod();
}, 1000);
}
main(myEventEmitter);
2.4 使用定时器制定函数执行计划
3 main constructors:
- setTimeout()
- setInterval()
- process.nextTick()
sample code:
/**
demonstration of add constraint to event handle sequences
*/
// 1 delay to handle in the next round event loop
process.nextTick(function(){
console.log("I should be executed in next event loop");
});
// 2 blocking the event loop: so act well to follow the rules
/*
process.nextTick(function(){
while(true){
console.log(".");
}
});
process.nextTick(function(){
console.log("I should never be executed.");
});
setTimeout(function(){
console.log("now timeout");
}, 1000);
*/
// 3 sequence all executions
function myAsyncFunction(func){
setTimeout(function(){
func();
}, 1500);
}
(function sequence(){
setTimeout(function do_it(){
myAsyncFunction(function(){
console.log("async is done now");
sequence();
});
}, 1000);
}()); // execute immediately