首页 > 编程语言 >[NodeJS] timers阶段的源码解析

[NodeJS] timers阶段的源码解析

时间:2024-07-04 20:08:24浏览次数:19  
标签:node 定时器 handle NodeJS uv timer queue 源码 timers

timers阶段是Nodejs事件循环中的一个阶段,这一阶段主要是检查是否有到期的定时器,如果有则执行其回调。

相关源码位置:

timers阶段的代码比较少,这里直接贴出来,你也可以点进去上面的源码看自己感兴趣的部分:

void uv__run_timers(uv_loop_t* loop) {
  struct heap_node* heap_node;
  uv_timer_t* handle;
  struct uv__queue* queue_node;
  struct uv__queue ready_queue;
  
  // 初始化一个空的 ready_queue 队列,用于存放已经到期的定时器
  uv__queue_init(&ready_queue);

  for (;;) {
    // 获取堆中最小(即最早到期)的定时器节点
    heap_node = heap_min(timer_heap(loop));
    if (heap_node == NULL)
      break;  // 如果堆是空的(没有定时器),则跳出循环

    // 将堆节点转换为 uv_timer_t 类型的定时器句柄 handle
    handle = container_of(heap_node, uv_timer_t, node.heap);
    if (handle->timeout > loop->time)
      break;  // 如果当前定时器的超时时间大于当前的循环时间,则跳出循环

    // 停止到期的定时器,并将其插入到 ready_queue 队列的尾部
    uv_timer_stop(handle);
    uv__queue_insert_tail(&ready_queue, &handle->node.queue);
  }
  
  // 处理 ready_queue 中的所有定时器
  while (!uv__queue_empty(&ready_queue)) {
    queue_node = uv__queue_head(&ready_queue);  // 取出队列头部的节点
    uv__queue_remove(queue_node);  // 移除该节点
    uv__queue_init(queue_node);  // 重新初始化节点
    handle = container_of(queue_node, uv_timer_t, node.queue);  // 将节点转换为定时器句柄 handle

    // 重新启动定时器,如果是重复定时器,则根据设定的间隔重新计算超时时间
    uv_timer_again(handle);
    // 调用定时器的回调函数,执行定时器到期后的操作
    handle->timer_cb(handle);
  }
}

内容比较少,这里也直接贴出来:

int uv_timer_again(uv_timer_t* handle) {
  if (handle->timer_cb == NULL)
    return UV_EINVAL;

  if (handle->repeat) {
    uv_timer_stop(handle);
    uv_timer_start(handle, handle->timer_cb, handle->repeat, handle->repeat);
  }

  return 0;
}

可以看到会检查handle->repeat,这里其实就是setTimeoutsetInterval的区别了,setInterval到这里会因为handle->repeattrue而重新开启新的一轮计时,而setTimeout则是直接跳过、结束了。

这里的handle->repeatuint64_t类型,其实就是timeout

这里顺便贴一下uv_timer_start的代码,感兴趣可以看看。

源码位置:node/deps/uv/src/timer.c at main · nodejs/node (github.com)

int uv_timer_start(uv_timer_t* handle,
                   uv_timer_cb cb,
                   uint64_t timeout,
                   uint64_t repeat) {
  uint64_t clamped_timeout;
  
  // 如果定时器正在关闭或回调函数为 NULL,则返回错误代码 UV_EINVAL
  if (uv__is_closing(handle) || cb == NULL)
    return UV_EINVAL;
  
  // 停止定时器,以确保定时器在重新启动前没有在运行
  uv_timer_stop(handle);
  
  // 计算定时器的超时时间 clamped_timeout
  // 它是当前事件循环时间 handle->loop->time 加上 timeout
  clamped_timeout = handle->loop->time + timeout;
  // 如果发生整数溢出,导致 clamped_timeout 小于 timeout,
  // 则将 clamped_timeout 设置为最大值 UINT64_MAX
  if (clamped_timeout < timeout)
    clamped_timeout = (uint64_t) -1;

  // 设置定时器的回调函数、超时时间和重复间隔
  handle->timer_cb = cb;
  handle->timeout = clamped_timeout;
  handle->repeat = repeat;
  
  // start_id 用于在定时器比较函数 timer_less_than 中作为第二索引进行比较
  // 并递增事件循环的计时器计数器
  handle->start_id = handle->loop->timer_counter++;

  // 将定时器插入到事件循环的定时器堆中,并启动定时器句柄
  heap_insert(timer_heap(handle->loop),
              (struct heap_node*) &handle->node.heap,
              timer_less_than);
  uv__handle_start(handle);

  return 0;
}
  • clamped_timeouttimeout之间的关系:

    • timeout 是传递给 uv_timer_start 函数的参数,表示定时器的初始延迟时间,以毫秒为单位;

    • clamped_timeout 是计算后的绝对时间,表示定时器实际超时的绝对时间点(以事件循环的时间 handle->loop->time 为基准)。

  • uv_timer_starttimeoute参数 和 JS中setTimeoutdelay参数是等价的。

标签:node,定时器,handle,NodeJS,uv,timer,queue,源码,timers
From: https://www.cnblogs.com/feixianxing/p/18284332/nodejs-event-loop-timers

相关文章

  • 工厂车间管理系统的设计/工厂车间管理系统/车间管理软件/工厂生产管理系统/车间生产流
    前言......
  • 源码编译构建LAMP
    Apache简介        主要特点                开放源代码,跨平台应用                支持多种网页编程语言                模块化设计,允行稳定,良好的安全性        编译安装httpd服务器       ......
  • [NodeJS] NodeJS事件循环
    JS是单线程的,如果出现阻塞会严重影响代码执行效率。NodeJS通过事件循环,尽可能地将耗时任务委派给系统内核来实现非阻塞IO。NodeJS提供了许多和异步相关的API,除了语言标准规定的setTimeout和setInterval,还有setImmediate和process.nextTick。经常和这几个出现在面试题里的还有Pr......
  • 预约上门按摩小程序(APP+H5)源码交付成品系统
    在这个风和日丽的午后,给大家带来一个非常实用、便捷且高效的产品——预约上门按摩小程序源码系统!这不仅仅是一个小程序,更是一个能够让你轻松预约专业按摩师上门服务的神器哦!大家在日常生活中,是不是经常感到工作压力大,肩颈酸痛,想找个按摩师舒缓一下,却不知道去哪里找?或者找到了,......
  • 记录一下使用小程序反编译获取源码
    起因是自己开发的小程序源码被扒了,泄露了一些数据,要做优化调整代码,所以尝试扒自己开发的小程序源码。安装node.jswxappUnpacker(逆向反编译工具)使用夜神模拟器(直接是root默认,手机需要进入root模式,就是模拟器比较卡)实操流程如下打开wxappUnpacker所在文件夹,cmd进入命令......
  • Python Linux源码安装
    保留服务器原Python安装版本,安装指定需求版本Python1.查看当前系统版本[root@iZbp1ac4pv22mg092qi2zfZ~]#cat/etc/system-releaseCentOSLinuxrelease7.9.2009(Core)2.查看已安装Python路径及版本[root@iZbp1ac4pv22mg092qi2zfZ~]#whichpython/usr/bin/python[ro......
  • 基于java+springboot+vue实现的校园外卖服务系统(文末源码+Lw)292
    摘   要传统信息的管理大部分依赖于管理人员的手工登记与管理,然而,随着近些年信息技术的迅猛发展,让许多比较老套的信息管理模式进行了更新迭代,外卖信息因为其管理内容繁杂,管理数量繁多导致手工进行处理不能满足广大用户的需求,因此就应运而生出相应的校园外卖服务系统。本......
  • 基于java+springboot+vue实现的宠物商城网站(文末源码+Lw)273
    摘   要传统信息的管理大部分依赖于管理人员的手工登记与管理,然而,随着近些年信息技术的迅猛发展,让许多比较老套的信息管理模式进行了更新迭代,商品信息因为其管理内容繁杂,管理数量繁多导致手工进行处理不能满足广大用户的需求,因此就应运而生出相应的宠物商城网站。本宠物......
  • 数字人直播源码开发全攻略揭秘:如何搭建自己的数字人直播平台?
    当前,数字人直播逐渐成为众多中小型企业线上带货和品牌宣传的不二之选,而艾媒研究数据也显示,超五成以上的被调查群体的企业使用过虚拟人技术,超三成被调查群体的企业计划使用虚拟人技术。在此背景下,越来越多的创业者通过数字人直播源码开发,以获得入局分羹的资格似乎是顺理成章的事......
  • 阿基米德算法优化变分模态分解AOA-VMD数字信号去噪(优化K值 alpha值 )【含Matlab源码 48
    ......