JavaScript基础(四)防抖

2019-03-15  本文已影响0人  前端开发爱好者

需求

在日常的前端开发中,一般会遇到一些会被频繁触发的事件,比如:window.resize,window.scroll,mousedown,mousemovekeydown,keyup,或者输入框等。这些函数或者是事件一般会被非常频繁的触发。

方案

为了解决这个问题一般会有两种解决方案:防抖(debounce)和节流(throttle)

防抖

原理:假定时间间隔是n秒。那么就是在函数第一次被调用时延时n秒后执行。在这n秒期间之内,再次触发,则以新的事件为准

第一版实现

function deBounce(func, wait) {
    var timeFlag;
    return function () {
        clearInterval(timeFlag);
        timeFlag = setTimeout(func, wait)
    }
}

第二版实现

第一版实现中会存在this指向不正确的问题


function deBounce(func, wait) {
    var timeFlag;
    return function () {
        var context = this;
        clearInterval(timeFlag);
        timeFlag = setTimeout(function () {
            func.apply(context)
        }, wait)
    }
}

或者使用bind
function deBounce(func, wait) {
    var timeFlag;
    return function () {
        clearInterval(timeFlag);
        timeFlag = setTimeout(func.bind(this), wait)
    }
}

第三版实现

第二版中的实现存在传参的问题

function deBounce(func, wait) {
    var timeFlag;
    return function () {
        var context = this;
        var args = arguments
        clearInterval(timeFlag);
        timeFlag = setTimeout(function () {
            func.apply(context, args)
        }, wait)
    }
}

或者bind

function deBounce(func, wait) {
    var timeFlag;
    return function (...args) {
        clearInterval(timeFlag);
        timeFlag = setTimeout(func.bind(this, ...args), wait)
    }
}

或者es6
const deBounce = (func, wait) => {
    let timeFlag;
    return function (...args) {
        clearInterval(timeFlag);
        timeFlag = setTimeout(func.bind(this, ...args), wait)
    }
};

第四版实现

有时会有需要立即执行的需求。

function deBounce(func, wait, immediate) {
    var timeFlag;
    return function () {
        var context = this;
        var args = arguments;
        timeFlag && clearInterval(timeFlag);
        if (immediate) {
            var callNow = !timeFlag;
            timeFlag = setTimeout(function () {
                timeFlag = null
            }, wait);
            if (callNow) func.apply(context, args)
        } else {
            timeFlag = setTimeout(function () {
                func.apply(context, args)
            }, wait)

        }
    }
}
// 或者

const deBounce = (func, wait, immediate) => {
    let timeFlag;
    return function (...args) {
        clearInterval(timeFlag);
        if (immediate) {
            const oldFlag = !timeFlag;
            timeFlag = setTimeout(() => {
                timeFlag = null
            }, wait);
            oldFlag && func.apply(this, args)
        } else {
            timeFlag = setTimeout(func.bind(this, ...args), wait)
        }
    }
};

第五版

第四版的函数仍然存在部分问题。就是当函数立即执行时。可能需要函数的返回值,所以修改后有下面第五版

function deBounce(func, wait, immediate) {
    var timeFlag;
    var deBounced = function () {
        var context = this;
        var args = arguments;
        var result;
        timeFlag && clearInterval(timeFlag);
        if (immediate) {
            var callNow = !timeFlag;
            timeFlag = setTimeout(function () {
                timeFlag = null
            }, wait);
            if (callNow) result = func.apply(context, args)
        } else {
            timeFlag = setTimeout(function () {
                func.apply(context, args)
            }, wait)

        }
        return result
    };
    deBounced.cancel = function () {
        clearTimeout(timeout);
        timeout = null;
    };
    return deBounced;
}

// es6
const deBounce = (func, wait, immediate) => {
    let timeFlag;
    const deBounced = (...args) => {
        clearInterval(timeFlag);
        if (immediate) {
            const oldFlag = !timeFlag;
            timeFlag = setTimeout(() => {
                timeFlag = null
            }, wait);
            oldFlag && func.apply(this, args)
        } else {
            timeFlag = setTimeout(func.bind(this, ...args), wait)
        }
    };
    deBounced.cancel = () => {
        clearTimeout(timeFlag);
        timeFlag = null;
    };
    return deBounced
};
上一篇下一篇

猜你喜欢

热点阅读