setTimeout
setTimeout
是在指定时间间隔后将其插入到执行队列中,但是若他之前有运行时间较长的程序,则其执行时间可能比指定时间晚。
分析以下代码:
//part1:some code here,it may cost a lot time
var timer1 = setTimeout(function(){
//part2:some code here,it may cost a lot time
var timer2 = setTimeout(arguments.callee,1000);
},1000);
问:time1
在1s后将其插入到执行队列,但是它是在1s后执行的吗?
答:是不一定,若part1
执行时间超过1s则time1
的执行时间比1s晚。
问:time2
是在time1
执行开始后1s执行的吗?
答:是不一定,若part2
执行时间超过1s则不是。
setInterval
setInterval
是在指定时间间隔后将定时器插入到执行队列中。但是定时器中的代码执行时间过长的话,两个定时器间隔可能变小,且有的定时器可能被越过。
分析以下代码:
var timer3 = setInterval(function(){
//part3:some code here,it may cost a lot time
},1000);
若part3
的执行时间为3000
,假设在1s
后将第1个time3
插入到执行队列,当part3运行到1000
的时候,将第2个time3
副本插入到执行队列,当part3运行到2000的时候,由于定时器队列中已经有1个定时器实例了,因此第3个time3
副本将不会被插入到执行队列,当part3
运行结束的时候,立即运行第2个time3
副本,(此时第1个time3
和第2个time3
之间没有事件间隔),并在定时器队列中插入第4个time3
副本。
实质上,setTimeout和setInterval会被插入到定时器观察值内部的红黑树中,而每次事件循环迭代从红黑数中取出定时器对象需要耗费性能,时间复杂度为
O(logn)
,所以setTimeout(fn,0)
较浪费性能;都返回一个唯一数值,表示计时器间隔,目的是取消计数时器。
process.nextTick
process.nextTick
是将其插入到当前循环队列末尾.早于setTimeout(function(){},0);
可以理解为setTimeout0
是在下次循环开始,而process.nextTick
结束后本次循环才完成,但是Promise.resolve()
是在process.nextTick
之后执行的。
setImmediate
setImmediate
是真正将其插入到下次循环队列末尾。
new Promise(function () {
console.log('promise');
});
Promise.resolve().then(function () {
console.log('resolve');
});
setTimeout(function () {
console.log('setTimeout')
}, 0);
setImmediate(function () {
console.log('Immediate')
});
process.nextTick(function () {
console.log('tick')
});
setInterval(function () {
console.log('interval')
},0);
console.log('outer');
输出结果:
promise
outer
tick
resolve
setTimeout
interval
Immediate
interval
interval
interval
setTimeout和闭包题目
for(var i = 0; i<3; i++){
setTimeout(
say,
(function () {
var b = i*1000;
console.log(b);
return b;
})(),
i
);
}
function say(msg) {
console.log('****** '+msg);
}
以上输出:
0
1000
2000
****** 0
****** 1
****** 2
因为setTimeout
的第3
个参数每次将当前的i
传递给say
方法。
而下面的执行结果中i
保留的是最后的全局i
:
for(var i = 0; i<3; i++){
setTimeout(
function(){
say(i);
},
(function () {
var b = i*1000;
console.log(b);
return b;
})()
);
}
function say(msg) {
console.log('****** '+msg);
}
输出结果为:
0
1000
2000
****** 3
****** 3
****** 3
setTimeout
的第一个参数在node环境下必须是函数,否则会出错,但是在浏览器端可以不是,下面成语在浏览器端执行:
for(var i = 0; i<3; i++){
setTimeout(
(function(a){
say(a);
})(i),
(function () {
var b = i*1000;
console.log(b);
return b;
})()
);
}
function say(msg) {
console.log('****** '+msg);
}
输出:
****** 0
0
****** 1
1000
****** 2
2000
可见当setTimeout
第一个参数为立即执行函数时的确会立即执行,在解析的时候就执行。