Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

防抖和节流 #2

Open
TieMuZhen opened this issue Nov 12, 2021 · 0 comments
Open

防抖和节流 #2

TieMuZhen opened this issue Nov 12, 2021 · 0 comments

Comments

@TieMuZhen
Copy link
Owner

TieMuZhen commented Nov 12, 2021

一、防抖节流异同比较

相同点:

  • 都可以通过使用setTimeout实现。
  • 目的都是,降低回调执行频率。节省计算资源。

不同点:

  • 函数防抖:在一段连续操作结束后,处理回调,利用clearTimeoutsetTimeout实现。函数节流:在一段连续操作中,每一段时间只执行一次,频率较高的事件中使用来提高性能。
  • 函数防抖关注一定时间连续触发的事件只在最后执行一次,而函数节流侧重于一段时间内只执行一次(如技能冷却)。

二、防抖函数实现

常用版

/**
 * delay 延迟多久后执行
 */
function debounce(fn, delay) {
    var timer; // 维护一个 timer
    return function () {
        var _this = this; // 取debounce执行作用域的this
        var args = [...arguments];
        if (timer) {
            clearTimeout(timer);
        }
        timer = setTimeout(function () {
            fn.apply(_this, args); // 用apply指向调用debounce的对象,相当于_this.fn(args);
        }, delay);
    };
}

测试用例:

// test
function testDebounce(e, content) {
    console.log(e, content);
}
var testDebounceFn = debounce(testDebounce, 1000); // 防抖函数
document.onmousemove = function (e) {
    testDebounceFn(e, 'debounce'); // 给防抖函数传参
}

高配版

/**
 * fn 传入的要防抖的函数
 * wait 多久执行的时间阈值
 * immediate 为 true 时,表示函数在每个等待时延的开始被调用。immediate 为 false 时,表示函数在每个等待时延的结束被调用。
 */
function debounce(func, wait, immediate = true) {
    let timeout;
    // 延迟执行函数
    // 因为setTimeout内this为全局,context参数是为了改变setTimeout内部this指向以便需要的时候使用 
    const later = (context, args) => setTimeout(() => {
        timeout = null; // 倒计时结束
        if (!immediate) {
            //执行回调
            func.apply(context, args);
            // 将闭包内变量赋值为null,用于垃圾回收
            context = args = null;
        }
    }, wait);
    let debounced = function () {
        let args = arguments;
        if (!timeout) {
            timeout = later(this, args);
            if (immediate) { // 第一次点击马上执行
                func.apply(this, args);
            }
        } else {
            clearTimeout(timeout);
            //函数在每个等待时延的结束被调用
            timeout = later(this, args);
        }
    }
    //提供在外部清空定时器的方法
    debounced.cancel = function () {
        clearTimeout(timeout);
        timeout= null;
    };
    return debounced;
};

使用

用debounce来包装scroll的回调
const better_scroll = debounce((log) => console.log(log), 1000);
document.addEventListener('scroll', better_scroll("滚动事件防抖"))

防抖的应用场景

  • 搜索框输入查询,如果用户一直在输入中,没有必要不停地调用去请求服务端接口,等用户停止输入的时候,再调用,设置一个合适的时间间隔,有效减轻服务端压力。
  • 表单验证
  • 按钮提交事件。
  • 浏览器窗口缩放,resize事件(如窗口停止改变大小之后重新计算布局)等。

三、节流函数实现

常用版

function throttle(fn, delay) {
    var previous = 0;
    // 使用闭包返回一个函数并且用到闭包函数外面的变量previous
    return function() {
        var now = new Date();
        if(now - previous > delay) {
            fn.apply(this, arguments);
            previous = now;
        }
    }
}

测试用例:

// test
function testThrottle(e, content) {
    console.log(e, content);
}
var testThrottleFn = throttle(testThrottle, 1000); // 节流函数
document.onmousemove = function (e) {
    testThrottleFn(e, 'throttle'); // 给节流函数传参
}

高配版

/**
 * fn 传入的要节流的函数
 * wait 多久执行的时间阈值
 */
function throttle(fn, wait) {
    let timer, pre = 0;
    const throttle = function () {
        const context = this; // 保留调用时的this上下文
        const args = arguments; // 保留调用时传入的参数
        let now = +new Date();
        if (now - pre < wait) {
            clearTimeout(timer);
            timer = setTimeout(() => {
                pre = now;
                fn.apply(context, args);
            }, wait);
        } else {
            pre = now;
            fn.apply(context, args);
        }
    }
    throttle.cancel = function () {
        clearTimeout(timer);
        timer = null;
    }
    return throttle;
}

const fn = function (log) {
    console.log(log);
}
const better_scroll = throttle(fn, 1000);
document.addEventListener("scroll", better_scroll("添加节流"));

节流的应用场景

  • 按钮点击事件
  • 拖拽事件
  • onScoll
  • 计算鼠标移动的距离(mousemove)

参考文献

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant