0%

pro-node 之 event

events 模块是 node 中的基础模块,很多内置模块都继承于它,像 stream…

基本用法

1
2
3
4
5
6
var events = require("events");
var emitter = new events.EventEmitter();
emitter.emit("foo");
emmiter.on("foo", function() {
console.log("foo event happened ...");
});
  • on(“event”,handler)

  • once(“event”,handler) 同 on,只接受一次

  • emit(“event”,arg1,arg2…)

  • add/remove/removeAll Listener 字面意思

  • setMaxListeners 设置最大 listener 的数量

  • listeners(event_name)函数返回 listener 数组,不提供 event name 的话,返回空数组

特殊事件newListener

1
2
3
4
5
6
7
8
9
10
11
require("d:/js/start.js");

var emitter = new ev.EventEmitter();

emitter.on("newListener", function() {
console.log("新添加了监听器...");
});

emitter.on("newListener", function() {
console.log("新添加了监听器2...");
});

输出

1
新添加了监听器...

没有手动调用 emit,却有事件触发了,及特殊之处,在调用 on/addListener/once 等添加 listener 的方法会触发 newListener 事件,尝试使用数组一条语句添加两个 listener,报错,listener must be a function

继承 EventEmitter 做法
有见到

1
2
3
4
5
function Abc() {
EventEmitter.call(this);
//其他属性附加到this
}
util.inherits(Abc, EventEmitter);

关于继承

当初看了语言精髓,不是精粹,绿皮国人写的,比较详细,以为都搞懂了,现在连 Object.create 都记不起来了,来理理总结下吧

  • prototype
  • __proto__,Object.getPrototype,Object.isPrototypeOf
  • Object.create
  • util.inherits
  • util._extend

首先__proto__是对象的,prototype是函数构造器的
__proto__ = constructor.prototype的,也就是

1
2
3
function Abc() {}
var abc = new Abc();
abc.__proto__ == abc.constructor.prototype; //true

然后我将 Object.getPrototypeOf Object.isPrototype 和__proto__写在一起,是因为底层就是__proto__,而 node 已经可以使用__proto__

1
2
abc.__proto__.isPrototypeOf(abc); //true
abc.__proto__ == Object.getPrototypeOf(abc); //true

Object.create(__proto__,props);
指定__proto__属性和其他的属性创建对象,这个 props 中可以写 value writable enumerable 等,下面 node 标准库的 util.inherits 会调用这个


util.inherits(subClass,baseClass)
两个构造器,继承,看源码

1
2
3
4
5
6
7
8
9
10
11
exports.inherits = function(ctor, superCtor) {
ctor.super_ = superCtor;
ctor.prototype = Object.create(superCtor.prototype, {
constructor: {
value: ctor,
enumerable: false,
writable: true,
configurable: true
}
});
};

前面 Abc 继承 EventEmitter 类,abc = new Abc()

  • Abc.super_ = EventEmitter
  • Abc.prototype =
    { __proto__ : EventEmitter.prototype , constructor : Abc }

这个 inherits 重置了一个构造器(Abc)的 prototype,导致在 inherits 调用之前的 Abc.prototype.self_method 被舍弃,为了取到 EventEmitter 构造器的部分,需要 EventEmitter.call(this),其实可以将 EventEmitter.prototype 改为 new EventEmitter(),只是这个构造函数不具备通用性,可能有其他参数.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var util = require("util");

function Base() {
this.name = "base name";
}
Base.prototype.base_method = function() {
console.log("base_method...");
};

function A() {
Base.call(this);
}
util.inherits(A, Base);
A.prototype.self_method = function() {
console.log("self_method...");
};

var a = new A();

a.base_method();
a.self_method(); //先定义self_method,后inherits会,因为重置了A.prototype报错

util._extend(origin,add)
源码

1
2
3
4
5
6
7
8
9
10
11
exports._extend = function(origin, add) {
// Don't do anything if add isn't an object
if (!add || typeof add !== "object") return origin;

var keys = Object.keys(add);
var i = keys.length;
while (i--) {
origin[keys[i]] = add[keys[i]];
}
return origin;
};

简单看,就是合并 add 至 origin

我的实践
__proto__是很危险的,不要重置它,默认是指向 constructor.prototype 的

类继承用

  • util.inherits,注意在内部调用基类构造函数,call(this),后面紧接着调用 util.inherits
  • 手动指定 sub.prototype = new Base();当然 constructor 属性 = Base,可以重置回来
    sub.prototype.constructor = sub;

Timer and Intervals

1
2
3
4
5
var timeoutId = setTimeout(callback, time);
clearTimeout(id);

var intervalId = setInterval(callback, time);
clearInterval(id);

不多介绍
ref() , unref()方法
在 C#的 Console Program 中为了停住看下结果,使用的是 Console.ReadLine(),按回车终止…,可是 node 的程序,只要有事件循环(event loop),timeout,interval 还没执行完的话,程序就不会退出,如果只有一个 timeout or interval 在运行的话,使用 id.unref()来使这个 timeout or interval 不执行了

1
2
3
4
var id = setTimeout(function() {
console.log("5000ms passed ...");
}, 5000);
id.unref();

这样程序就不会等待五秒退出,而是立即退出…
ref()是 unref()的方向操作

process.nextTick 在下一个事件循环处执行回调
setImmediate/clearImmediate 立即事件