简单说说函数节流和防抖

582 阅读2分钟

定时器

目的:延时执行代码或者间隔执行某行代码。

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()

函数防抖和函数节流

参考1 参考2 参考3

鼠标滑动实例对比

函数防抖(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();