我看遍了所有中文资料的 unref 资料,发现全是错的。。也是醉了。
官方文档:https://nodejs.org/dist/latest-v5.x/docs/api/timers.html#timers_unref
来自:http://www.jb51.net/article/57861.htm
如果这个引用正确的话,那么《Node.js权威指南》这本书里的解释也是错的。
网上大部分的说法都说 unref 会暂停一个回调函数的调用,可实测的代码如下
var timer = setInterval(function () {
console.log(new Date, 1)
}, 1000)
var timer2 = setInterval(function () {
console.log(new Date, 2)
}, 1000)
timer2.unref()
timer2 始终没有被暂停。
按我对于文档的理解,unref 的意思只是让 timer 不会阻止 node 进程的退出,类似垃圾回收时候的引用计数-1的感觉。但不管是否调用了 unref,回调函数都会一直运行。
为了搜索引擎能过来,我堆点关键词:
javascript中setTimeout和setInterval的unref()和ref()
nodejs中的全局函数setTimeout/clearTimeout,setInterval/clearInterval,unref/ref
6666
取消不是 clearTimeout / clearInterval 么~哈哈
你上面的匿名函数是不行,但写成这种是可以的 var testFunction=function(){
console.log("can cancel?");
}
var timer=setInterval(testFunction,1000);
timer.unref();//取消setTimeout和setInterval的调用
timer.ref();//恢复setTimeout和setInterval的调用 unref取消的是它调用的函数
var timer = setInterval(function () {
console.log(new Date, 1)
}, 1000)
var fn = function () {
console.log(new Date, 2)
}
var timer2 = setInterval(fn, 1000)
timer2.unref()
你真的跑过?
@alsotang 根据你提供的官网文档, 这个地方but if it is the only item left in the event loop, it won't keep the program running
指明如果调用了unref
函数的定时器在事件循环中是仅存在的一个, 那么程序不会继续运行下去, 测试了下:
a> var timer = setInterval(function () {
console.log(new Date, 1)
}, 1000)
var fn = function () {
console.log(new Date, 2)
}
var timer2 = setInterval(fn, 1000)
timer2.unref()
函数中a处如果被注释掉, 此时相当于事件循环队列中只有一个timer2因此程序退出,如果把a处的setInterval换成setTimeout即让timer也仅运行一次, 那么timer和timer2都只会允许一次, 我理解的是timer 在的时候timer2在事件队列中不是唯一的因此它会继续执行.然而如果不调用unref
函数不管怎么样程序都会一直运行下去
针对handle而言,判断loop是否存活只要看loop->active_handles是否大于0,大于0则存活。
具体代码参看 https://github.com/libuv/libuv/blob/v1.x/src/uv-common.h
uv__handle_init, uv__handle_start, uv__handle_stop, uv__handle_ref, uv__handle_unref
比较下面几种情况,可能会有利于理解unref的作用。
第一种
var timer1 = setTimeout(function(){
console.log(new Date, 1);
}, 1000);
// setTimeout=>uv_timer_start(timer1) active_handles = 1
var timer2 = setInterval(function(){
console.log(new Date, 2);
}, 1000);
// setInterval=>uv_timer_start(timer2) active_handles = 2
// 1: ative_handles > 0 => loop()
// timer1 timeout => uv_timer_stop(timer1) active_handles = 1 => callback()
// timer2 timeout => uv_timer_stop(timer2) active_handles = 0 => callback() => uv_timer_start(timer2) active_handles = 1
// 2: active_handles > 0 => loop()
// timer2 timeout => uv_timer_stop(timer2) active_handles = 0 => callback() => uv_timer_start(timer2) active_handles = 1
// goto 2
第二种
var timer1 = setTimeout(function(){
console.log(new Date, 1);
}, 1000);
// setTimeout=>uv_timer_start(timer1) active_handles = 1
var timer2 = setInterval(function(){
console.log(new Date, 2);
}, 1000);
// setInterval=>uv_timer_start(timer2) active_handles = 2
timer2.unref();
// uv_unref(timer2) active_handles = 1
// ative_handles > 0 => loop()
// timer1 timeout => uv_timer_stop(timer1) active_handles = 0 => callback()
// timer2 timeout => uv_timer_stop(timer2) active_handles = 0 => callback() => uv_timer_start(timer2) active_handles = 0
// active_handles == 0 => exit_process
第三种
var timer1 = setInterval(function(){
console.log(new Date, 1);
}, 1000);
// setInterval=>uv_timer_start(timer1) active_handles = 1
var timer2 = setInterval(function(){
console.log(new Date, 2);
}, 1000);
// setInterval=>uv_timer_start(timer2) active_handles = 2
// 1: ative_handles > 0 => loop()
// 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 1
第四种
var timer1 = setInterval(function(){
console.log(new Date, 1);
}, 1000);
// setInterval=>uv_timer_start(timer1) active_handles = 1
var timer2 = setInterval(function(){
console.log(new Date, 2);
}, 1000);
// setInterval=>uv_timer_start(timer2) active_handles = 2
timer2.unref()
// uv_unref(timer2) active_handles = 1
// 1: ative_handles > 0 => loop()
// timer1 timeout => uv_timer_stop(timer1) active_handles = 0 => callback() => uv_timer_start(timer1) active_handles = 1
// timer2 timeout => uv_timer_stop(timer2) active_handles = 1 => callback() => uv_timer_start(timer2) active_handles = 1
// goto 1
第五种
var timer1 = setInterval(function(){
console.log(new Date, 1);
}, 1000);
// setInterval=>uv_timer_start(timer1) active_handles = 1
timer1.unref()
// uv_unref(timer1) active_handles = 0
var timer2 = setInterval(function(){
console.log(new Date, 2);
}, 1000);
// setInterval=>uv_timer_start(timer2) active_handles = 1
timer2.unref()
// uv_unref(timer2) active_handles = 0
// ative_handles == 0 => exit process
@alsotang 和 @ncuzp 的理解是正确的,主要还是看循环是否结束,循环结束了,进程退出了,回调函数当然不会执行了。
uv__hanlde_init(handle) => handle->flags = UV__HANDLE_REF
uv__handle_unref(handle) 清除 handle->flags上的UV__HANDLE_REF位,没有被ref标记位,uv__handle_start(handle), uv__handle_stop(handle) 就不会影响loop->active_handles。
一些文章要么是错的,要么是过时的,最好还是直接去看源代码。https://github.com/libuv/libuv/blob/v1.x/src/uv-common.h
@coordcn 受教
@coordcn 赞
@coordcn 受教
@coordcn 受教
学习了~~
@coordcn 666,涨知识
@coordcn 向大神学习,感叹知道的好少
@coordcn 学习了,看了express-rate-limit这个中间件的实现 ,里面有用到unref,当时也不理解。 ‘use strict’; function MemoryStore(windowMs) { var hits = {};
this.incr = function(key, cb) {
if (hits[key]) {
hits[key]++;
} else {
hits[key] = 1;
}
cb(null, hits[key]);
};
this.resetAll = function() {
hits = {};
};
// export an API to allow hits from one or all IPs to be reset
this.resetKey = function(key) {
delete hits[key];
};
// simply reset ALL hits every windowMs
var interval = setInterval(this.resetAll, windowMs);
if (interval.unref) {
interval.unref();
}
}
module.exports = MemoryStore;
专门注册一个账号膜拜大佬~~