JS函数防抖与节流

函数节流和防抖在前端开发中应用广泛,例如:函数防抖可以用于对用户输入的自动补全操作、函数节流可以用于对用户浏览行为的捕捉。

防抖

函数在事件触发 n 秒后才执行,如果一个事件触发的 n 秒内又触发了这个事件,那就以新的事件的触发时间为准

基本版
function denounce(func, wait) {
    var timeout;
    return function (){
        clearTimeout(timeout);
        setTimeout(func, wait);
    }
}
解决 setTimeout 执行过程中 this 指向问题
function debounce (func, wait){
    var timeout
    return function (){
        var that = this
        clearTimeout(timeout)
        timeout = setTimeout(function(){
            func.apply(that)
        }, wait)
    }
}
解决 event 参数传递
function debounce (func, wait){
    var timeout
    return function (){
        var args = arguments
        var that = this
        clearTimeout(timeout)
        timeout = setTimeout(function(){
            func.apply(that, args)
        }, wait)
    }
}
加上可立即执行判断
function debounce (func, wait, immediate){
    var timeout
    return function (){
        var args = arguments
        var that = this
        clearTimeout(timeout)
        if (immediate){
            if (!timeout){
                func.apply(that, args)
            }
            timeout = setTimeout(function(){
                timeout = null
            }, wait)
        } else {
            timeout = setTimeout(function(){
                func.apply(that, args)
            }, wait)
        }
    }
}
加上返回值
function debounce (func, wait, immediate){
    var timeout, result
    return function (){
        var args = arguments
        var that = this
        clearTimeout(timeout)
        if (immediate){
            if (timeout){
                result = func.apply(that, args)
            }
            timeout = setTimeout(function(){
                timeout = null
            }, wait)
        } else {
            timeout = setTimeout(function(){
                func.apply(that, args)
            }, wait)
        }
        return result
    }
}
增加取消上次防抖等待
function debounce (func, wait, immediate){
    var timeout, result
    var debounced = function (){
        var args = arguments
        var that = this
        clearTimeout(timeout)
        if (immediate){
            if (!timeout){
                result = func.apply(that, args)
            }
            timeout = setTimeout(function(){
                timeout = null
            }, wait)
        } else {
            timeout = setTimeout(function(){
                func.apply(that, args)
            }, wait)
        }
        return result
    }
    debounced.cancel = function(){
        clearTimeout(timeout)
        timeout = null
    }
    return debounced    
}

节流

函数在每个规定时间间隔内只会被触发一次

两种基本方式
时间戳版(效果:第一次触发马上执行,最后一次触发不会有效果)
function throttle(func, wait) {
    var pre = 0
    return function(){
        var now = Date.now()
        var that = this
        var args = arguments
        if (now - pre > wait) {
            func.apply(that, args)
            pre = now
        }
    }
}
定时器版(效果:第一次触发延迟执行,最后一次触发有效果)
function throttle(func, wait){
    var timeout
    return function(){
        var that = this
        var args = arguments
        if (!timeout) {
            timeout = setTimeout(function (){
                timeout = null;
                func.apply(that, args)
            }, wait)
        }
    }
}
结合可配置版
function throttle(func, wait, options) {
    var timeout, context, args, result;
    var previous = 0;
    if (!options) options = {};

    var later = function() {
        previous = options.leading === false ? 0 : new Date().getTime();
        timeout = null;
        func.apply(context, args);
        if (!timeout) context = args = null;
    };

    var throttled = function() {
        var now = new Date().getTime();
        if (!previous && options.leading === false) previous = now;
        var remaining = wait - (now - previous);
        context = this;
        args = arguments;
        if (remaining <= 0 || remaining > wait) {
            if (timeout) {
                clearTimeout(timeout);
                timeout = null;
            }
            previous = now;
            func.apply(context, args);
            if (!timeout) context = args = null;
        } else if (!timeout && options.trailing !== false) {
            timeout = setTimeout(later, remaining);
        }
    };
    return throttled;
}

推荐阅读更多精彩内容

  • 前言 最近和前端的小伙伴们,在讨论面试题的时候。谈到了函数防抖和函数节流的应用场景和原理。于是,想深入研究一下两者...
    youthcity阅读 9,796评论 4 43
  • 概念 函数防抖(debounce) 当调用动作过n毫秒后,才会执行该动作,若在这n毫秒内又调用此动作则将重新计算执...
    yuanjiex阅读 104评论 0 1
  • pdf下载地址:Java面试宝典 第一章内容介绍 20 第二章JavaSE基础 21 一、Java面向对象 21 ...
    王震阳阅读 77,501评论 25 510
  • 在前端开发的过程中,我们经常会需要绑定一些持续触发的事件,如 resize、scroll、mousemove 等等...
    淘淘笙悦阅读 58,482评论 29 140
  • 一、概念 函数节流和函数防抖,两者都是优化高频率执行js代码的一种手段。 旧款电视机的工作原理,就是一行行得扫描出...
    木子川页心阅读 87评论 0 0