nodejs定时器setInterval,setTimeout,clearTimeout, clearInterval源码学习

本文深入探讨Node.js的定时器机制,包括setInterval、setTimeout、clearTimeout、clearInterval以及unref()的失效情况。通过分析C++源码,解释了timer.unref()在特定情况下为何失效,以及定时器的创建过程和内部工作原理,如TimerWrap、事件循环和超时检查等。
摘要由CSDN通过智能技术生成

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);

即调用的是HandleWrapUnref方法:

// 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是否在activeactive_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 
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值