定时器
目的:延时执行代码或者间隔执行某行代码。
setTimeout()
设置一个定时器,在定时器到期后执行一个函数或指定的一段代码。
var timeoutID = window.setTimeout(function|code,delay)
- function|code(不建议使用字符串): 你可以执行函数或者字符串。
- delay: 延迟的毫秒数(一秒等于1000毫秒)
- timeoutID返回值是定时器的编号,这个值可以传递给clearTimeout()来取消该定时器。 举例
function f(){
console.log(2);
}
setTimeout(f,1000);
或者
setTimeout(function f(){
console.log(2);
},1000);
超时调用的代码都是在全局作用域下执行的,this在非严格模式下指向window对象
setInterval()
运行机制
setTimeout和setInterval的运行机制:将指定的代码移出本次执行,等到下一轮Event Loop时,再检查是否到了指定时间。如果到了,就执行对应的代码;如果不到,就等到再下一轮Event Loop时重新判断。
这意味着,setTimeout指定的代码,必须等到本次执行的所有代码都执行完,才会执行。
例子
setTimeout(function(){
console.log(1);
},0)
console.log(2);
// 2 1
setTimeout(f,0)不会现在就立刻执行,而是在现有任务结束后立刻执行即等console.log(2)执行后才执行
var i = 0;
for(var i = 0; i < 10; i++){
setTimeout(function(){
console.log(i);
},1000)
}
先执行for循环,执行完成后i的值变为10,然后过了一秒钟才执行setTimeout,这时i早已变成10了,相当于1秒之后执行了10个定时器。
var t = true;
setTimeout(function(){
t = false;
}, 1000);
while(t){ }
console.log('end')
因为while(t){ }无限循环被卡死。
异步与回调
同步
函数b等函数a执行完成才执行
function a(){}
function b(){}
a();
b();
异步
function a(){
setTimeout(function(){
console.log(2);
},1000);
}
function b(){}
a();
b();
//2
以上为异步代码,先执行函数a,再执行setTimeout之前执行函数b,等待执行至少1s的时候执行console.log(2)。setTimeout代码放在任务队列里,先执行函数b,等主线程空闲才将队列里等待的回调函数进行执行。
回调
回调函数:即函数被当作参数传入另外一个函数当中,并在那个函数中被调用回调只是异步的一种实现方式。
异步:
function f1(){
setTimeout(function(){
//做某件事,可能很久
console.log('别急,开始执行f1')
for(var i=0;i< 100000;i++){
}
console.log('f1执行完了')
}, 0);
}
function f2(){
console.log('执行f2');
}
function f3(){
console.log('执行f3');
}
f1()
f2()
f3()
//执行f2
//执行f3
//别急,开始执行f1
//f1执行完了
f1()中有异步处理,先执行f2()、f3()、再执行f1()。
回调:
function f1(callback){
setTimeout(function(){
//做某件事,可能很久
console.log('别急,开始执行f1')
for(var i=0;i< 100000;i++){
}
console.log('f1执行完了')
callback()
}, 0);
}
function f2(){
console.log('执行f2');
}
function f3(){
console.log('执行f3');
}
f1(f2)
f3()
以上代码中f1()中有异步代码。先执行f3(),再执行f1(),最后执行f1()中的f2()
函数防抖和函数节流
函数防抖(debounce)
在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时 应用场景:
function debounce(func,delay){
var timer = null;//用来存放定时器返回值
return function(){
clearTimeout(timer)//重新计算时间
timer = setTimeout(function(){
func.apply(this,arguments)
}, delay);//定时器的id
}
}
function func(){
console.log('do something');
}
var fn = debounce(func,1000)
//输入多个fn()
fn()
fn()
fn()
函数节流(throttle)
规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效。
应用场景:
- 大量事件时间平均触发
- 防止多次点击按钮计时造成速度加快
function throttle(func, delay) {
var canUse = true;//闭包保存一个标记
return function(){
if(canUse){//canUse为true
func.apply(this,arguments);//方法放在外面,该函数是异步的
canUse = false
setTimeout(function(){
canUse = true //在执行完毕后设置为true可以进行下一次执行
}, delay);
}
}
}
function func(){
console.log('hello ');
}
var fn2 = throttle(func, 1000);
fn2();
fn2();
fn2();