本模块,属于来模拟一些浏览器自带方法的模块,比如setTimeout,clearTimeout等方法,之所以会有该模块,在我看来,也是为了能让前端工程师使用起来,更简单,使用一个单独的模块,来把浏览器上的功能来模拟出来,那么就可以直接减少学习的成本,这样就可以花更少的时间,学习到更多的东西。
timers模块中,使用的C++的方法
timers模块中,调用了C++实现的方法,这些方法,在该模块中,占据了很重要的位置,所以,这里我们先来看下,在C++的方法中,提供了哪些方法。
var Timer = process.binding('timer_wrap').Timer; console.log(Timer);
运行之后,在控制台,就会打印出如下的内容,它的格式如下
{ [Function: Timer] // Timer构造函数,可以进行实例化 kOnTimeout: 0, // 静态属性,公用,更改会影响其他的调用 now: [Function: now] // 静态方法,获取类似时间戳的一个数字 }
其中,Timer本身是一个构造函数,而这个构造函数中,还包含了一个静态属性和一个静态方法,关于静态属性和方法,基本上,这两个只是拿来使用的,是禁止修改的,并且,其使用方法比较简单,所以这里不多说了。
Timer既然还是一个构造函数,那么久是可以被实例化的,接下来,看下实例化之后的对象:
var Timer = process.binding('timer_wrap').Timer, timer = new Timer(), i = ""; console.log("obj has attribute:"); console.log(timer); console.log("prototype method and attribute:"); for(i in timer){ console.log(i+"="+timer[i]); }
把上面的代码,执行的结果如下:
obj has attribute: {} prototype method and attribute: close=function close() { [native code] } ref=function ref() { [native code] } unref=function unref() { [native code] } start=function start() { [native code] } stop=function stop() { [native code] } setRepeat=function setRepeat() { [native code] } getRepeat=function getRepeat() { [native code] } again=function again() { [native code] }
从上面的结果中可以看出,在Timer实例化之后,在对象本身,是没有属性和方法的,在原型链上,是有一些方法,至于这些方法,有什么用,就需要慢慢去看一下了。
timers模块中的一个基础--构造函数Timeout
之所以这里要把这个构造函数以单小节的形式给出,是因为在我看来,如果想要对整个timers模块中的逻辑有更好的认识,那么该模块的基础一个私有的构造函数的理解,还是很有必要的。
这里,我们首先来看一下源码:
var Timeout = function(after) { // 定义内部属性,过时时间 this._idleTimeout = after; // 循环链表中的两个属性,可以参考前篇文章linklist私有模块 this._idlePrev = this; this._idleNext = this; // 记录开始计时时间的属性 this._idleStart = null; // 当时间到了,执行的回调函数 this._onTimeout = null; // 该计时器,是否需要repeat,setInterval方法,该属性为true this._repeat = false; }; function unrefdHandle() { // unref方法的回调函数,内部this指向Timeout._handle属性 // 在该属性上,定义了owner属性,保存Timeout的实例化后的对象 this.owner._onTimeout(); if (!this.owner._repeat) this.owner.close(); } Timeout.prototype.unref = function() { // 这个方法,是用来暂停计时器的 // 添加一个新的属性_handle用来对接C++提供的API接口 if (!this._handle) { // 做一些初始的判断属性,设置初始值等 var now = Timer.now(); if (!this._idleStart) this._idleStart = now; var delay = this._idleStart + this._idleTimeout - now; if (delay < 0) delay = 0; // 把this指向的计时器对象,清理掉,从计时器链表中清理掉 exports.unenroll(this); // 介入C++提供的API方法 this._handle = new Timer(); // 添加一些属性,用来保存一些信息 this._handle.owner = this; this._handle[kOnTimeout] = unrefdHandle; // 开始计时,在delay后执行改方法的回调 this._handle.start(delay, 0); this._handle.domain = this.domain; // 调用C++提供的方法,停止计时器的执行 this._handle.unref(); } else { // 如果之前有_handle属性,那么则直接停止 this._handle.unref(); } }; Timeout.prototype.ref = function() { // 该方法,只有在unref之后,才起作用,恢复计时器的工作 // 如果在unref中,生成了_handle属性,那么使用该属性 // 调用C++提供的API,ref,恢复计时器的运行 if (this._handle) this._handle.ref(); }; Timeout.prototype.close = function() { // 当要关闭计时器对象时,如果定义过接入C++饿API的方法时 // 直接使用C++的方法,关闭 // 否则,把该方法,清理出去 // 不让它再lists链表中,那么当计时器执行到时,也不会执行该计时器的回调函数 this._onTimeout = null; if (this._handle) { this._handle[kOnTimeout] = null; // 调用C++中提供的close方法,见前面构造函数Timer的原型链方法中 this._handle.close(); } else { exports.unenroll(this); } };