Node.js组成及Events模块
1 Node.js的模块和包
1.1模块
Node.js本身提供许多模块,每个模块实现一种功能,如文件操作模块fs
,构建HTTP服务的http
模块等,每个模块都是一个javascript文件,可以自己编写模块。
每一个Node.js都是一个Node.js模块,包括JavaScript文件(.js
)、JSON文本文件(.json
)和二进制模块文件(.node
)
1.1.1 模块的使用
模块内使用module.exports
和exports
对外提供接口,便于在其他模块中引入要使用的模块,新建模块module.js
,并对外提供接口。
使用exports
提供接口
function hello() {
console.log("Hello");
}
function world() {
console.log("World");
}
exports.hello = hello;
exports.world = world;
使用module.exports
提供接口
function Hello() {
this.hello = function() {
console.log("Hello");
};
this.world = function() {
console.log("World");
};
}
module.exports = Hello;
1.1.2 引用模块
使用require()
引用创建的模块,参数是模块的路径。
引用exports
提供接口的模块
var hello = require("./test.js");
hello.hello(); //==> Hello
hello.world(); //==> World
引用module.exports
提供接口的模块
//module.exports导出的是Hello函数,将其保存到Test变量中
var Test = require("./test.js");
//将Test()当做构造起函数,创建对象来使用
var demo = new Test();
demo.hello(); //==> Hello
demo.world(); //==> World
1.2 module.exports
和exports
区别
每个模块中都有一个module
对象,module
是当前模块的一个引用。module.exports
对象是由Module
系统构建的,exports
可以看做module.exports
对象的引用。
在require()
一个模块时,以module.exports
的值为准,在有的情况下module.exports
和exports
的值不同。
// module.exports和exports相同的情况
var m = {}; // 表示 module
var e = m.e = {}; // e 表示 exports, m.e 表示 module.exports
m.e.a = 5;
e.b = 6;
console.log(m.e); // Object { a: 5, b: 6 }
console.log(e); // Object { a: 5, b: 6 }
// module.exports和exports不同的情况
var m = {}; // 表示 module
var e = m.e = {}; // e 表示 exports, m.e 表示 module.exports
m.e = { c: 9 }; // m.e(module.exports)引用的对象被改了
e.d = 10;
console.log(m.e); // Object { c: 9 }
console.log(e); // Object { d: 10 }
1.2 包
包可以将多个具有依赖关系的模块组织在一起,将多个模块封装,便于管理。
Node.js采用CommonJS规范,一个javascript文件就是一个模块,包是一个文件夹,包内必须包含一个名为package.json
的JSON文件。
包内bin
文件夹内存放二进制文件,lib
文件夹存放javascript文件,doc
文件夹存放文档,test
文件夹存放单元测试。
1.2.1包的目录
包的目录必须包含package.json
文件,CommonJS用来描述包,应该包含以下字段:
-
name
:包的名字,唯一,只能包含字符、下划线和数字; -
version
:包的版本号; -
description
:包的说明; -
keywords
:关键字数组,用于搜索; -
homepage
:项目主页; -
bugs
:提交bug的地址; -
liciense
:许可证; -
maintainers
:维护者数组; -
contributors
:贡献者数组; -
repositories
:项目仓库托管地址数组; -
dependencies
:包依赖。
实例:
{
"name": "Kyxy",
"description": "Kyxy test package.",
"version": "0.1.0",
"keywords": [
"kyxy",
"nodejs"
],
"maintainers": [{
"name": "test",
"email": "test@kyxy.com"
}],
"contributors": [{
"name": "test",
"web": "http://www.kyxy.com/"
}],
"bugs": {
"mail": "test@kyxy.com",
"web": "http://www.kyxy.com/"
},
"licenses": [{
"type": "Apache License v2",
"url": "http://www.apache.org/licenses/apache2.html"
}],
"repositories": [{
"type": "git",
"url": "http://github.com/test/test.git"
}],
"dependencies": {
"webkit": "1.2",
"ssl": {
"gnutls": ["1.0", "2.0"],
"openssl": "0.9.8"
}
}
}
1.3 npm包管理工具
npm是Node.js
的包管理工具,npm定义了包依赖关系标准,使用npm下载第三方包和管理本地下载的第三方包。
查询包信息:
npm info express
安装包:
sudo npm install express
更新包:
sudo npm update express
卸载包:
sudo npm uninstall express
2 Events
模块
Node.js
中,许多对象会发出事件:fs.readStream
打开一个文件时会发出一个事件。所有发出的事件对象都是events.EventEmitter
的实例,可以通过require("events");
获得events
模块。
事件命名推荐使用驼峰命名法。将函数添加到对象,对象发出事件时,相应函数被执行(这些函数被称为监听器);先将函数赋予对象(设为监听器),在对象发出事件时调用该函数
2.1 Class: events.EventEmitter
通过require("events").EventEmitter
获取 EventEmitter
类。当EventEmitter
对象遇到错误时,触发error
事件;
error
事件在Node.js
中是一种特殊事件,(如果没有设置error
事件触发的监听器),默认打印出栈跟踪器,并退出程序。
2.2 添加监听器
为事件添加监听器有两种方法,作用完全相同:参数事件(event
),处理函数(listener
)
-
emitter.addListener(event, listener)
: -
emitter.on(event, listener)
: 一直监听
//import http module
var http = require("http");
//create a http server
var server = http.createServer();
//bind a listener for server`s request Event
server.on("request", function(req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write("Tracy");
console.log("Kyxy");
res.end();
});
//listen ip:127.0.0.1 port:1337, if requested, execute the listener function
server.listen(1337, "127.0.0.1");
console.log('Server running at http://127.0.0.1:1337/');
运行上述代码,在浏览器地址栏输入127.0.0.1:1337,可以看到Tracy
,同时控制台输出Kyxy
2.3 只执行一次的监听器
使用emitter.once(event, listener)
方法绑定的事件监听器只会执行一次,然后事件被删除。
var http = require('http');
var server = http.createServer();
// 为request事件绑定处理函数,事件只会执行一次
server.once('request', function(req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('shiyanlou');
console.log('shiyanlou');
res.end();
});
server.listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');
运行上述代码,在浏览器地址栏输入127.0.0.1:1337,可以看到Tracy
,同时控制台输出Kyxy
。再刷新页面,就不会再显示,因为事件只会执行一次。
2.4 移除监听器
使用emitter.removeListener(event, listener)
方法移除为对象的request
事件绑定的处理函数。
//import http module
var http = require("http");
//create a http server
var server = http.createServer();
function callback(req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write("Hello World");
console.log("Hello World");
res.end();
}
//bind a listener for server`s request Event
server.on("request", callback);
//remove a listener for server`s request Event
server.removeListener("request", callback);
server.on("request", function(req, res) {
res.writeHead(200, { 'Content-Type': 'text/json' });
res.write("I`m back");
console.log("LMD");
res.end();
});
//listen ip:127.0.0.1 port:1337, if requested, execute the listener function
server.listen(1337, "127.0.0.1");
console.log('Server running at http://127.0.0.1:1337/');
运行上述代码,在浏览器地址栏输入127.0.0.1:1337,可以看到I
m back,同时控制台输出
LMD,但是没有
Hello World,因为监听器
callback`被移除了。
2.4 移除所有监听器
使用emitter.removeAllListeners([event])
,移除对象上监听event
事件的所有监听器。
//import http module
var http = require("http");
//create a http server
var server = http.createServer();
function talk(req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write("haha");
console.log("xixi");
res.end();
}function fruit(req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write("apple");
console.log("leomon");
res.end();
}
//bind listeners for server`s request Event
server.on("request", talk);
server.on("request", fruit)
//remove listeners from server`s request Event
server.removeAllListeners("request");
server.on("request", function(req, res) {
res.writeHead(200, { 'Content-Type': 'text/json' });
res.write("I`m back");
console.log("LMD");
res.end();
});
//listen ip:127.0.0.1 port:1337, if requested, execute the listener function
server.listen(1337, "127.0.0.1");
console.log('Server running at http://127.0.0.1:1337/');
移除绑定在server
上的所有事件监听器,所以只显示I
m back,输出
LMD`。
2.5 设置监听器的最大绑定数
emitter.setMaxListeners(n)
可以设置同一事件可以绑定的监听器的最大数目,默认情况下,超过10个就会提示警告信息(可以帮助找到内存泄漏的地方),不是所有的事件触发器都限制在10个,可以通过这个方法设置,如果设置为0就是无限制。
2.6 自定义事件
使用emitter.emit(event, [arg1], [arg2], [...])
,可以触发自定义事件。
//import http module
var http = require("http");
//create a http server
var server = http.createServer();
server.on("myevent", function(arg) {
console.log(arg);
});
server.emit("myevent", "Kyxy");
server.on("request", function(req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write("Tracy");
res.end();
});
//listen ip:127.0.0.1 port:1337, if requested, execute the listener function
server.listen(1337, "127.0.0.1");
console.log('Server running at http://127.0.0.1:1337/');
2.7 查看事件绑定的监听器个数
使用events.EventEitter.listenerCount(emitter, event)
可以查看事件监听器的数量。
var http = require("http");
var events = require("events");
var server = http.createServer();
server.on("request", function(req, res) {
res.writeHead(200, {"Content-Type": "text/plain"});
res.write("kyxy");
console.log("kyxy");
res.end();
});
server.on("request", function(req, res) {
res.writeHead(200, {"Content-Type": "text/plain"});
res.write("Tracy");
console.log("Tracy");
res.end();
});
server.listen(1337, "127.0.0.1");
console.log('Server running at http://127.0.0.1:1337/');
var num = events.EventEmitter.listenerCount(server, "request");
console.log(num); //2
控制台界面输出了数字2
,因为server绑定了两个监听器到'request'
事件。