1,事件循环机制
Node.js 在什么时候会进入事件循环呢?答案是 Node.js 程序由事件循环开始,到事件循
环结束,所有的逻辑都是事件的回调函数,所以 Node.js 始终在事件循环中,程序入口就是
事件循环第一个事件的回调函数。事件的回调函数在执行的过程中,可能会发出 I/O 请求或
直接发射(emit)事件,执行完毕后再返回事件循环,事件循环会检查事件队列中有没有未
处理的事件,直到程序结束。
2,事件
Node.js 所有的异步 I/O 操作在完成时都会发送一个事件到事件队列。在开发者看来,事
件由 EventEmitter 对象提供。前面提到的 fs.readFile 和 http.createServer 的回
调函数都是通过 EventEmitter 来实现的。 下面我们用一个简单的例子说明 EventEmitter
的用法:
var EventEmitter = require('events').EventEmitter;
var event = new EventEmitter();
event.on('some_event', function() { //事件的注册:event.on(“事件名称”,回调函数)
console.log('some_event occured.');
});
setTimeout(function() {
event.emit('some_event'); //事件的触发:event.emit('事件名称');
}, 1000);
运行这段代码,1秒后控制台输出了 some_event occured. 。 其原理是 event 对象注册了事件 some_event 的一个监听器,然后我们通过 setTimeout 在1000毫秒以后向
event 对象发送事件 some_event ,此时会调用 some_event 的监听器。
3,node的工作原理
一开始的请求可能是I/o请求,网络通信请求,数据库查询请求,都是一个请求事件,都会进入node的事件循环机制里面,事件循环发现对应的请求以后就会调用相应的回调函数,
回调函数处理完之后,又会回到事件循环机制里面,查看还有没有其它的事件请求
4, package原理
Node.js 在调用某个包时,会首先检查包中 package.json 文件的 main 字段,将其作为
包的接口模块,如果 package.json 或 main 字段不存在,会尝试寻找 index.js 或 index.node 作
为包的接口。
5, node.js工具
(1) node.js 的全局变量:global
如 global.A="1111";
Node.js常用工具
1:util util是node.js的核心模块,提供常用的函数集合,用于 弥补核心JavaScript的功能过于精简的不足
util.inherits(constructor,superConstructor) 是一个实现对象间圆形继承的函数
util.inspect(object,xxx) 是一个将任意对象转换为字符串的方法
util.isArray(object) 如果给定的参数object是一个数组还回true,否则返回false ,下面同理
util.jsRegExp(object)
util.isDate(object);
uitl.isError(object)
2: fs模块封装的是文件系统,它提供了文件的读取,写入,更名,删除,遍历目录,链接等
读取文件内容函数:异步方法:fs.readFile()
同步方法:fs.readFileSync()
3 : fs.open(path,flags,xxx)
4: fs.read(fd,buffer,offset,length,position,xxx) 5: 常用的工具类:util和事件EventEmitter util.inherits(constructor , superConstructor) util.inherits(Sub,Base);//让Sub继承Base接口,这样Sub就有Base的扩展属性了
var util=require('util');
function Base() {
this.name='base';
this.base=2012;
this.sayHello=function(){
console.log('hello'+this.name+'this year is '+this.base);
};
}
Base.prototype.showName=function(){
console.log(this.name);
}
function Sub(){
this.name='sub';
}
//原型继承
util.inherits(Sub,Base);//让Sub继承Base接口,这样Sub就有Base的扩展属性了
var objBase=new Base();
objBase.showName();
objBase.sayHello();
console.log(objBase);
objSub.showName();
console.log(objSub);
6: util inspect(object);
此方法是一个将任意对象转换成字符串的方法
7:events是node.js最重要的模板
evetns.EventEmitter,EventEmitter的核心就是事件发射与时间监听器功能的封装
//首先引入工具类
var events=require('events');
//实例化事件对象
var emitter=new events.EventEmitter();
//注册事件监听器1
emitter.on('someEvent', function (arg1, arg2) {
console.log('listener1',arg1,arg2);
});
//注册事件监听器2
emitter.on('someEvent', function (arg1, arg2) {
console.log('listener2',arg1,arg2);
});
//触发事件
emitter.emit('someEvent','zlm1323',1991);
emitter.once();//注册一个单次监听器
removeListener()
8:error事件
EventEmitter定义了一个特殊的事件error
9: fs模块 是文件操作的封装,它提供了文件的读取,写入,更名,删除,遍历目录。与其他模块不同的是fs模块中所 有的操作都提供了 异步和同步两个版本:读取文件类容: 异步方法:readFile() 同步方法:readFileSync();
10: http模块
//引入模块
var http=require('http');
//创建服务
var server=http.createServer(function(req,res){
//响应头
res.writeHead(200,{'Content-Type':'text/plain'});
//响应内容
res.write('<h1>Node.js</h1>h1>');
//响应结束
res.end('Hello World\n');
});
server.listen(1888);
console.log("Server Running at 8888")
http:提供了三个事件用于控制请求体传输 serverRequest
(1):data,当请求体数据到来时,该事件被触发,改事件一共一个参数chunk,表示接受到的参数
(2):end,当请求体数据传输完成时,该事件被触发,以后将不会再有数据到来
(3):close,用户当前请求结束时,该事件被触发,不用于end,如果用户强制终止了传输,也会触发close
11: 请求
Node.js 的异步编程接口习惯是以函数的最后一个参数为回调函数,通
常一个函数只有一个回调函数。回调函数是实际参数中第一个是 err ,其
余的参数是其他返回的内容。如果没有发生错误, err 的值会是 null 或
undefined 。如果有错误发生, err 通常是 Error 对象的实例。
get请求:
var http = require('http');
var url = require('url');
var util = require('util');
http.createServer(function(req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end(util.inspect(url.parse(req.url, true)));
}).listen(3000);
post请求:
var http = require('http');
var querystring = require('querystring');
var util = require('util');
http.createServer(function(req, res) {
var post = '';
req.on('data', function(chunk) {
post += chunk;
});
req.on('end', function() {
post = querystring.parse(post);
res.end(util.inspect(post));
});
}).listen(3000);
上面代码并没有在请求响应函数中向客户端返回信息,而是定义了一个 post 变量,用
于在闭包中暂存请求体的信息。 通过 req 的 data 事件监听函数, 每当接受到请求体的数据,
就累加到 post 变量中。在 end 事件触发后,通过 querystring.parse 将 post 解析为
真正的 POST 请求格式,然后向客户端返回。
6, Http客服端
http 模块提供了两个函数 http.request 和 http.get ,功能是作为客户端向 HTTP
服务器发起请求。
http.request(options, callback) 发起 HTTP 请求
http.get(options, callback) http 模块还提供了一个更加简便的方法用于处
理GET请求: http.get 。 它是 http.request 的简化版, 唯一的区别在于 http.get
自动将请求方法设为了 GET 请求,同时不需要手动调用 req.end() 。
http.ClientRequest 是由 http.request 或 http.get 返回产生的对象,表示一
个已经产生而且正在进行中的 HTTP 请求。
7, node.js调试方法:
node的第一种调试技巧:1:进入需要调试的js脚本文件所在目录
2:cmd窗口 node --debug-brk=5858 test.js
3:重新打开另一个cmd窗口: node-inspector
4:最后chorme浏览器中输入:
http://127.0.0.1:8080/?ws=127.0.0.1:8080&port=5858
8, 总结
1:导出模块 exports
nodejs里面有个特殊的变量:module,它代表当前模块自身,而module.exports是模块对外导出的对象,
它可以是任何对象,
2 : 加载模块 require函数可以加载某个模块
3:模块大约分为几种类型:核心模块 , 本地模块 , 和通过NPM安装的第三方模块
4:根据模块的类型,可以分为几种不同的引用方式:
(1):核心模块不能通过路径来引用,只能用模块名加载,核心模块有最高的加载优秀级,即使已经有了
一个同名的第三方模块,核心模块也会被优先加载
如: var http=require('http');
(2):也可以使用绝对路径从文件系统里加载模块
var myModule=require('/home/pedro/my_modules/my_module')
如果是基于当前文件路径
var myModule2=require('./lib/my_module_2')
(3):加载目录模块 也可以使用目录的路径来加载模块
var myModule=require('./myModuleDir')
(4):从node_modules目录加载 ,如果require函数的参数不是相对路径,也不是核心模块
名,node会载当前目录的node_modules子目录下查找
如:var myModule=require('myModule.js')
小结
Node取消了JavaScript的默认全局作用域,转而采用CommonJS模块系统,这样你可以更好的组织你的代码,也因此避免了很多安全问题和bug。可以使用require函数来加载核心模块,第三方模块,或从文件及目录加载你自己的模块
还可以用相对路径或者绝对路径来加载非核心模块,如果把模块放到了node_modules目录下或者对于用NPM安装的模块,你还可以直接使用模块名来加载。