0
点赞
收藏
分享

微信扫一扫

前端优化中的防抖与截流


1. 什么是防抖?

在事件触发后的指定时间之后,再去执行真正需要执行的函数,如果在该时间之内事件又被触发,则重新开始计时。

常见的应用场景:

1. 滚动事件触发;

2. 搜索框输入查询;

3. 表单验证;

4. 按钮提交事件;

5. 浏览器窗口缩放;

以下是代码实现:

function debounce(func, time, immediate) {
    // 用来获取返回值
    let timer, result;

    let debounced = function () {
        // 保存当前指向
        let that = this;
        // 获取函数的参数
        let args = arguments;
        // 清除当前定时器
        clearTimeout(timer);
        // 立即执行
        if (immediate) { 
            let callNow = !timer;
            // 指定时间内不再执行
            timer = setTimeout(function () {
                timer = null;
            }, time);

            if (callNow){
                result = func.call(that, ...args);
            };

        // 不立即执行
        } else { 
            // 指定时间后触发函数
            timer = setTimeout(function () {
                // 改变函数内部指向,并传递参数
                func.call(that, ...args);

            }, time);
        };
        return result;
    };

    // 取消函数
    debounced.cancel = function () {
        // 清除定时器
        clearTimeout(timer); 
        // 定时器置空
        timer = null; 
    };
    // 返回防抖函数
    return debounced; 
}

2. 什么是截流?

在指定时间内触发多次函数的话,只有一次是可被执行的,下一次执行只能等到下一个周期里。

常见的应用场景:

1. DOM元素的拖拽功能实现;

2. 射击游戏;

3. 计算鼠标的移动距离;

4. 监听滚动事件;

截流函数根据是否立即执行,操作完成后是否还会执行一次,分为三种情况:

1. 用时间戳来实现。第一次立即执行,操作完成后不再执行;

function throttle(func, time) {
    let that, args;
    let old = 0;
    return function () {
        // 获取当前的时间戳
        let now = new Date().valueOf(); 
        // 保存当前指向
        that = this; 
        // 获取函数的参数
        args = arguments; 
        if (now - old > time) {
            // 改变函数内部指向,并传递参数
            func.apply(that, args); 
            // 更新旧时间戳
            old = now; 
        }
    }
};

2. 用定时器实现节流函数。第一次延时执行,操作完成后还会执行一次;

function throttle(func, time) {
    let that, args, timer;
    return function () {
        // 保存当前指向
        that = this;
        // 获取函数的参数
        args = arguments;
        if (!timer) {
            timer = setTimeout(function () {
                timer = null;
                func.apply(that, args);
            }, time);
        }
    }
};

3. 用时间戳与定时器结合实现截流函数。第一次立即执行,操作完成后还会执行一次;

function throttle(func, time) {
    let that, args, timer;
    let old = 0; 

    return function () {

        // 保存指向
        that = this;
        args = arguments;

        let now = new Date().valueOf(); 
        if (now - old > time) {
            if (timer) {
                clearTimeout(timer);
                timer = null;
            }
            func.apply(that, args);
            old = now;
        };

        if (!timer) {
            timer = setTimeout(function () {
                // 更新最新的时间戳
                old = new Date().valueOf(); 
                timer = null;
                func.apply(that,args);
            }, time);
        }
    }
}

最终版,用时间戳与定时器结合实现截流函数。根据参数来决定开始是否立即执行,结束后是否还会执行。

function throttle(func, time, options) { 
    let that, args, timer;
    // 设置初始时间戳
    let old = 0; 
    // 如果没有该参数,置为空对象
    if(!options){options = {}}; 

    return function () {
        that = this;
        args = arguments;

        // 获取初始的时间戳
        let now = new Date().valueOf(); 

        // leading为false表示不立即执行
        if (options.leading === false && !old) {
            old = now; 
        };

        if (now - old > time) { 
            if (timer) {
                clearTimeout(timer);
                timer = null;
            }
            func.apply(that, args);
            old = now;
        };

        // trailing为true表示最后一次会被执行
        if (!timer && options.trailing==true) { 
            timer = setTimeout(function () {
                // 更新最新的时间戳
                old = new Date().valueOf(); 
                timer = null;
                func.apply(that,args);
            }, time);
        }
    }
}

举报

相关推荐

0 条评论