nodejs Timer
本文章最好配合nodejs c语言源码一起,下面几个链接是相关的写的非常好的文章。
github优化资料
alinode源码
alinode TIme
nodejs timer解析
timer.unref()的失效情况
- 有效用法
下面的timer1
在创建后被unref
, 所以不会执行callback函数;
let timer1 = setInterval(()=>{
console.log('timer1...');
}, 1000);
timer1.unref();
- 失效用法
当同时存在2个timer
时,unref
函数失效, 两个定时器都会执行;
let timer1 = setInterval(()=>{
console.log('timer1...');
}, 1000);
let timer2 = setInterval(()=>{
console.log('timer2...');
}, 2000);
timer1.unref();
先看timer.unref
的底层调用
unref
对应的C++代码调用:
// timer_wrap.cc
constructor->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "Timer"));
...
env->SetProtoMethod(constructor, "unref", HandleWrap::Unref);
即调用的是HandleWrap
的Unref
方法:
// handle_wrap.cc
void HandleWrap::Unref(const FunctionCallbackInfo<Value>& args) {
HandleWrap* wrap;
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
if (IsAlive(wrap))
uv_unref(wrap->GetHandle());
}
// uv-common.cc
void uv_unref(uv_handle_t* handle) {
uv__handle_unref(handle);
}
uv-common.h
里面uv__handle_unref
干了两件事:
1) 取消REF位标记: (h)->flags &= ~UV__HANDLE_REF;
2) 如果timer
处于active状态, 则将活跃句柄-1: loop->active_handle--
;
对失效的解释
创建了2个timer后, node循环中, 有两个active_handles
:
let timer1 = ...
// setInterval=>uv_timer_start(timer1) => active_handles = 1
let time2 = ...
// setInterval=>uv_timer_start(timer2) => active_handles = 2
active_handles>0
激活loop
, 这里L1
为循环为标记点:
// L1: ative_handles > 0 => loop()
由于unref
只是标记了REF
, 这里还是执行了timeout
(TODO需要说明为什么还会执行??), 当timer1
到时后, 判断了active_handles=1
, loop
仍然处于acitve
, 所以会执行再次启动定时器uv_timer_start(timer1)
:
// timer1 timeout => uv_timer_stop(timer1) active_handles = 1 => callback() => uv_timer_start(timer1) active_handles = 2
// timer2 timeout => uv_timer_stop(timer2) active_handles = 1 => callback() => uv_timer_start(timer2) active_handles = 2
// goto L1
也就是说, 就是看loop
是否active
状态, 处于active
, 则会执行循环中的handle
, loop
是否在active
看active_handles
是否大于0;
#define uv__has_active_handles(loop) \
((loop)->active_handles > 0)
??? 具体为什么在unref后还会执行, 需要查验, REF标记对handle执行的影响
定时器的创建
setTimeout
为入口,
1. new Timeout();
这里的Timeout
对象timer时挂在TimerList
链表上的node, 所以其结构如下, 其中的_idlePrev
, _idleNext
为链表指针:
function Timeout(after, callback, args) {
this._called = false;
this._idleTimeout = after;
this._idlePrev