Node.js 中的定时器函数与web浏览器中的定时函数API 相似,增长了一个setImmediate() 函数,它们向任务队列添加定时任务node
setTimeout(callback, delay) delay毫秒后执行回掉函数
setInterval(callback,delay) 每隔delay毫秒执行一次回掉函数
setImmediate() 将在当前事件轮询的末尾处执行。同步任务执行完后,delay不为0时首先当即执行setImmediate() 函数
web
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服务器端返回响应头的这段时间, 若是超出设定时间,就终止请求bash
lib/timers.js
服务器
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;
}
复制代码
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方法恢复回掉函数的调用app
激活定时器对象,执行了 insert(item, true, getLibuvNow());async
function active(item) {
insert(item, true, getLibuvNow());
}
复制代码
将定时器对象添加到数据结构链表内tcp
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);
}
复制代码
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;
function clearTimeout(timer) {
if (timer && timer._onTimeout) {
timer._onTimeout = null;
unenroll(timer);
}
}
复制代码
移除定时器,不进行函数跟踪
以上是我的浅显的理解,刨的还不够深,道阻且长