Node timer 使用技巧和源码分析

栏目: 数据库 · 发布时间: 5年前

内容简介:Node.js 中的定时器函数与web浏览器中的定时函数API 类似,增加了一个setImmediate() 函数,它们向任务队列添加定时任务setTimeout(callback, delay) delay毫秒后执行回掉函数setInterval(callback,delay) 每隔delay毫秒执行一次回掉函数

Node.js 中的定时器函数与web浏览器中的定时函数API 类似,增加了一个setImmediate() 函数,它们向任务队列添加定时任务

介绍

setTimeout(callback, delay) delay毫秒后执行回掉函数

setInterval(callback,delay) 每隔delay毫秒执行一次回掉函数

setImmediate() 将在当前事件轮询的末尾处执行。同步任务执行完后,delay不为0时首先立即执行setImmediate() 函数

console.log("1")

setTimeout(func, 1000,10);
function func(num) {
    console.log("2")
  }
  
setImmediate(function(){console.log("3")}, 2000,10);

console.log("4")
//输出 1 4 3 2
复制代码

取消定时器,参数为每个定时器函数返回的定时器对象

clearTimeout(timeout)

clearInterval(timeout)

clearImmediate(immediate)

使用

//tcp服务端
var net = require('net')
var sever = net.createServer(function (connection) {
  //设置服务超时时间,并返回提示消息
  connection.setTimeout(1000, function () {
    console.log("响应超时.");
    connection.write('服务端响应超时了')
  });
  setTimeout(function () {
    connection.on('end', function () {
      //   console.log('客户端关闭连接')
    })
    connection.on('data', function (data) {
      console.log('服务端:收到客户端发送数据为' + data.toString())
    })
    //给客户端响应的数据
    connection.write('response hello')
  }, 5000)

})
sever.listen(8080, function () {
  console.log('监听端口:8080')
})
复制代码

HTTP服务器端开始发送响应数据到HTTP客户端接收全部数据的这段时间, 如果超出设定时间,则表示响应超时,并返回超时提示

var net = require('net')
var client = net.connect({
    port: 8080
})

//设置请求超时时间
client.setTimeout(3000);
//监听超时事件
client.on('timeout', function () {
    console.log("请求超时")
    //取消请求数据,不再发送请求
    client.destroy()
})
//客户端收到服务端执行的事件
client.on('data', function (data) {
    console.log('客户端:收到服务端响应数据为' + data.toString())
    client.end()
})
//给服务端传递的数据

client.write('hello')
client.on('end', function () {
    // console.log('断开与服务器的连接')
})
复制代码

客户端设置请求超时时间,HTTP客户端发起请求到接受到HTTP服务器端返回响应头的这段时间, 如果超出设定时间,就终止请求

源码分析

lib/timers.js

setTimeout函数定义

function setTimeout(callback, after, arg1, arg2, arg3) {
//第一个参数必须为函数
  if (typeof callback !== 'function') {
    throw new ERR_INVALID_CALLBACK(callback);
  }
//处理参数
//将第三个以后的参数包装成数组
  var i, args;
  switch (arguments.length) {
    // fast cases
    case 1:
    case 2:
      break;
    case 3:
      args = [arg1];
      break;
    case 4:
      args = [arg1, arg2];
      break;
    default:
      args = [arg1, arg2, arg3];
      for (i = 5; i < arguments.length; i++) {
        // Extend array dynamically, makes .apply run much faster in v6.0.0
        args[i - 2] = arguments[i];
      }
      break;
  }
    //生成一个Timeout 对象
  const timeout = new Timeout(callback, after, args, false);
  active(timeout);
//返回一个定时器对象
  return timeout;
}
复制代码

Timeout构造函数

const timeout = new Timeout(callback, after, args, false);

lib/internal/timers.js

生成的timer实例 表示Node.js层面的定时器对象,比如 setTimeout、setInterval、setImmediate返回的对象

function Timeout(callback, after, args, isRepeat) {
  after *= 1; // Coalesce to number or NaN
  if (!(after >= 1 && after <= TIMEOUT_MAX)) {
    if (after > TIMEOUT_MAX) {
      process.emitWarning(`${after} does not fit into` +
                          ' a 32-bit signed integer.' +
                          '\nTimeout duration was set to 1.',
                          'TimeoutOverflowWarning');
    }
    after = 1; // Schedule on next tick, follows browser behavior
  }
  //延迟时间
  this._idleTimeout = after;
  //前后指针
  this._idlePrev = this;
  this._idleNext = this;
  this._idleStart = null;
  // This must be set to null first to avoid function tracking
  // on the hidden class, revisit in V8 versions after 6.2
  this._onTimeout = null;
  //回调函数
  this._onTimeout = callback;
  //函数参数
  this._timerArgs = args;
  // setInterval的参数
  this._repeat = isRepeat ? after : null;
  // 摧毁标记
  this._destroyed = false;

  this[kRefed] = null;

  initAsyncResource(this, 'Timeout');
}
复制代码
Timeout.prototype.unref = function() {
  if (this[kRefed]) {
    this[kRefed] = false;
    decRefCount();
  }
  return this;
};

Timeout.prototype.ref = function() {
  if (this[kRefed] === false) {
    this[kRefed] = true;
    incRefCount();
  }
  return this;
};
复制代码

在Timeout构造函数原型上添加unref,ref方法

unref方法取消setTimeout()、setInterval()...回掉函数的调用

ref方法恢复回掉函数的调用

active激活定时器对象

激活定时器对象,执行了 insert(item, true, getLibuvNow());

function active(item) {
 insert(item, true, getLibuvNow());
}
复制代码

insert

将定时器对象添加到数据结构链表内

function insert(item, refed, start) {
//取出当前延迟时间
  let msecs = item._idleTimeout;
  //判断延迟时间
  if (msecs < 0 || msecs === undefined)
    return;

  // Truncate so that accuracy of sub-milisecond timers is not assumed.
  msecs = Math.trunc(msecs);
  item._idleStart = start;

  // Use an existing list if there is one, otherwise we need to make a new one.
  //根据延迟时间生成一个链表数据结构
  var list = timerListMap[msecs];
  if (list === undefined) {
    debug('no %d list was found in insert, creating a new one', msecs);
    const expiry = start + msecs;
    timerListMap[msecs] = list = new TimersList(expiry, msecs);
    timerListQueue.insert(list);

    if (nextExpiry > expiry) {
      scheduleTimer(msecs);
      nextExpiry = expiry;
    }
  }

  if (!item[async_id_symbol] || item._destroyed) {
    item._destroyed = false;
    initAsyncResource(item, 'Timeout');
  }

  if (refed === !item[kRefed]) {
    if (refed)
      incRefCount();
    else
      decRefCount();
  }
  item[kRefed] = refed;
// 把当前timeout对象添加到对应的链表上
  L.append(list, item);
}
复制代码

append()

node定时器是在生成对应list链表头的时候开始触发的

function append(list, item) {
 if (item._idleNext || item._idlePrev) {
   remove(item);
 }

 // 处理新节点的头尾链接.
 item._idleNext = list._idleNext;
 item._idlePrev = list;

 // 处理list的前后指针指向
 list._idleNext._idlePrev = item;
 list._idleNext = item;
}
复制代码

setInterval()函数的实现与setTimeout()函数类似,只有第二个参数的处理不同

const timeout = new Timeout(callback, repeat, args, true);

// setInterval的参数

this._repeat = isRepeat ? after : null;


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Tangled Web

The Tangled Web

Michal Zalewski / No Starch Press / 2011-11-26 / USD 49.95

"Thorough and comprehensive coverage from one of the foremost experts in browser security." -Tavis Ormandy, Google Inc. Modern web applications are built on a tangle of technologies that have been de......一起来看看 《The Tangled Web》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具