函数的防抖与节流实现

一、什么是节流函数,什么是防抖函数,它们之间的区别是什么?

·节流函数:节流,可以理解为节省流量。当一个请求被用户在短时间内不停点击时(用户频繁发送一个数据请求),为了减轻服务器压力,需要设定一个时间,使得在规定的这个时间内,无论用户请求了多少次,就当一次执行。例子:玩游戏回城按钮按多次等于按一次。

·防抖函数:抖,即抖动。当用户使用搜索框时,输入一个内容就发送一次请求,继续输入则会继续发送(用户一直在发送多个不同的请求),为了防止这种情况发生,应在用户输入结束后延时发请求,而不是同步发送。

·区别:节流函数是将多个重复的请求在规定的时间内执行一次,防抖是将一段时间内不停被执行的不同请求,延迟规定的时间后再执行。

二、节流函数与防抖函数的实现。

1.节流函数

------------------------------------------------------------------------------------------------------------------

//1.基础的节流函数,在规定的时间内执行只一次

function throttle(fn, delay) {
    //定义上一次的时间
    const lastTime = 0

    //真正执行的函数
    const doThrottle = function () {
        //定义当前调用的时间
        const nowTime = new Date().getTime()

        //如果当前调用的时间-上一次执行的时间比规定的时间小,即多次触发,则只执行一次
        if (delay <= (nowTime - lastTime)) {
            //外部传入的函数
            fn()
            lastTime = nowTime
        }
    }
    return doThrottle
}
 
------------------------------------------------------------------------------------------------------------------------

// 2.1控制节流第一次是否执行函数--leading

function throttle(fn, delay, options = { leading: true, trailing: false }) {
    //定义相关参数
    const { leading, trailing } = options
    const lastTime = 0

    //真正执行函数
    const doThrottle = function () {
        //定义当前调用时间
        const nowTime = new Date().getTime()

        //是第一次开始但是不希望执行函数
        if (lastTime === 0 && !leading) lastTime = nowTime

        //使用当前触发的时间-上一次执行时间与外部传入的时间比较
        const remainTime = delay - (nowTime - lastTime)
        if (remainTime <= 0) {
            //外部传入的函数
            fn()
            lastTime = nowTime
        }
    }
    return doThrottle
}
 
---------------------------------------------------------------------------------------------------------------------

// 2.2控制节流最后一次是否执行函数--leading,trailing

function throttle(fn, delay, options = { leading: true, trailing: false }) {
    //定义相关参数
    const { leading, trailing } = options
    const lastTime = 0
    const timer = null

    //真正执行函数
    const doThrottle = function () {
        //定义当前调用时间
        const nowTime = new Date().getTime()

        //是第一次开始但是不希望执行函数
        if (lastTime === 0 && !leading) lastTime = nowTime

        //使用当前触发的时间-上一次执行时间与外部传入的时间比较
        const remainTime = delay - (nowTime - lastTime)
        if (remainTime <= 0) {
            //防止重复调用
            if (timer) {
                clearTimeout(timer)
                timer = null
            }
            //外部传入的函数
            fn()
            //保留上次触发时间
            lastTime = nowTime
            return
        }
        //判断是否需要执行最后一次输出
        if (trailing && !timer) {
            timer = setTimeout(() => {
                //执行外部函数
                fn()
                //防止我们延迟调用函数时,上面时间到了后,又重复调用
                lastTime = !leading ? 0 : new Date().getTime()
                //清除定时器
                timer = null
            }, remainTime);
        }
    }
    return doThrottle
}
 
----------------------------------------------------------------------------------------------------------------------

//3.在上一次优化的前提上使用this

function throttle(fn, delay, options = { leading: true, trailing: false }) {
    //定义相关参数
    const { leading, trailing } = options
    const lastTime = 0
    const timer = null

    //真正执行函数
    const doThrottle = function (...args) {
        //定义当前调用时间
        const nowTime = new Date().getTime()

        //是第一次开始但是不希望执行函数
        if (lastTime === 0 && !leading) lastTime = nowTime

        //使用当前触发的时间-上一次执行时间与外部传入的时间比较
        const remainTime = delay - (nowTime - lastTime)
        if (remainTime <= 0) {
            //防止重复调用
            if (timer) {
                clearTimeout(timer)
                timer = null
            }
            //外部传入的函数
            fn.apply(this,args)
            //保留上次触发时间
            lastTime = nowTime
            return
        }
        //判断是否需要执行最后一次输出
        if (trailing && !timer) {
            timer = setTimeout(() => {
                //执行外部函数
                fn.apply(this,args)
                //防止我们延迟调用函数时,上面时间到了后,又重复调用
                lastTime = !leading ? 0 : new Date().getTime()
                //清除定时器
                timer = null
            }, remainTime);
        }
    }
    return doThrottle
}
 
-----------------------------------------------------------------------------------------------------------------

//4.在上一次优化的前提上添加取消功能

function throttle(fn, delay, options = { leading: true, trailing: false }) {
    //定义相关参数
    const { leading, trailing } = options
    const lastTime = 0
    const timer = null

    //真正执行函数
    const doThrottle = function (...args) {
        //定义当前调用时间
        const nowTime = new Date().getTime()

        //是第一次开始但是不希望执行函数
        if (lastTime === 0 && !leading) lastTime = nowTime

        //使用当前触发的时间-上一次执行时间与外部传入的时间比较
        const remainTime = delay - (nowTime - lastTime)
        if (remainTime <= 0) {
            //防止重复调用
            if (timer) {
                clearTimeout(timer)
                timer = null
            }
            //外部传入的函数
            fn.apply(this, args)
            //保留上次触发时间
            lastTime = nowTime
            return
        }
        //判断是否需要执行最后一次输出
        if (trailing && !timer) {
            timer = setTimeout(() => {
                //执行外部函数
                fn.apply(this, args)
                //防止我们延迟调用函数时,上面时间到了后,又重复调用
                lastTime = !leading ? 0 : new Date().getTime()
                //清除定时器
                timer = null
            }, remainTime);
        }
    }
    //取消功能,重置默认值
    doThrottle.cancel = function () {
        if (timer) clearTimeout(timer)
        timer = null
        lastTime = 0
    }
    return doThrottle
}
 
--------------------------------------------------------------------------------------------------------------------

//5.在上一次优化的前提上添加函数的返回值,使用回调函数callback

function throttle(fn, delay, options = { leading: true, trailing: false }, callback) {
    //定义相关参数
    const { leading, trailing } = options
    const lastTime = 0
    const timer = null

    //真正执行函数
    const doThrottle = function (...args) {
        //定义当前调用时间
        const nowTime = new Date().getTime()

        //是第一次开始但是不希望执行函数
        if (lastTime === 0 && !leading) lastTime = nowTime

        //使用当前触发的时间-上一次执行时间与外部传入的时间比较
        const remainTime = delay - (nowTime - lastTime)
        if (remainTime <= 0) {
            //防止重复调用
            if (timer) {
                clearTimeout(timer)
                timer = null
            }
            //返回外部函数调用结果
            const result = fn.apply(this, args)
            callback(result)
            //保留上次触发时间
            lastTime = nowTime
            return
        }
        //判断是否需要执行最后一次输出
        if (trailing && !timer) {
            timer = setTimeout(() => {
                //返回外部函数调用结果
                const result = fn.apply(this, args)
                callback(result)
                //防止我们延迟调用函数时,上面时间到了后,又重复调用
                lastTime = !leading ? 0 : new Date().getTime()
                //清除定时器
                timer = null
            }, remainTime);
        }
    }
    //取消功能,重置默认值
    doThrottle.cancel = function () {
        if (timer) clearTimeout(timer)
        timer = null
        lastTime = 0
    }
    return doThrottle
}

 

 

================================================================

================================================================

2.防抖函数

 

//1.创建一个基础的防抖函数,延迟执行

function debounce(fn, delay) {
    //定义一个定时器,保存上一次的定时器
    const timer = null;

    //执行函数
    const doDebounce = function () {
        //取消上一次的定时器
        if (timer) {
            clearTimeout(timer)
        }
        //延迟执行
        timer = setTimeout(() => {
            //外部传入的请求函数
            fn()
        }, delay)
    }
    return doDebounce
}
 
--------------------------------------------------------------------------------------------------------------------------

 

function debounce(fn, delay,) {
    //定义一次定时器,保存上一次的定时器
    const timer = null

    //真正执行的函数
    const doDebounce = function (...args) {
        //取消上一次的定时器
        if (timer) clearTimeout(timer)

        //延迟执行,参数不止一个,采用展开语法
        timer = setTimeout(() => {
            //外部传入真正要执行的函数
            fn.apply(this, args)
        }, delay)
    }

    return doDebounce
}
 
----------------------------------------------------------------------------------------------------------------

//3.在this的基础上判断是否立即执行

function debounce(fn, delay, immediate = false) {
    //定义一个定时器,保存上一次的定时器
    const timer = null
    const isDone = false

    //真正执行的函数
    const doDebounce = function (...args) {
        //取消上一次的定时器
        if (timer) clearTimeout(timer)

        //是否立即执行
        if (immediate && !isDone) {
            //即外部传入的immediate为真,则立即执行
            fn.apply(this, args)
            isDone = true
        }
        else {
            //延迟执行,参数不止一个,使用展开语法
            timer = setTimeout(() => {
                //外部传入执行函数
                fn.apply(this, args)
                isDone = false
            }, delay)
        }
    }
    return doDebounce
}
 
-----------------------------------------------------------------------------------------------------------

//4.在是否立即执行的基础上加入取消功能

function debounce(fn, delay, immediate = false) {
    //定义定时器,保存上一个
    const timer = null
    const isDone = false

    //真正执行函数
    const doDebounce = function (...args) {
        //清除上一个定时器
        if (timer) clearTimeout(timer)

        //是否立即执行
        if (immediate && !isDone) {
            fn.apply(this, args)
            isDone = true
        }
        else {
            //延迟执行
            timer = setTimeout(() => {
                fn.apply(this, args)
                isDone = false
            }, delay)
        }
    }

    //取消,由于函数也可作为对象使用,故添加一个重置函数
    doDebounce.cancel = function () {
        if (timer) clearTimeout(timer)
        timer = null
        isDone = false
    }

    return doDebounce
}
 
---------------------------------------------------------------------------------------------------------

//5.在加入取消功能上添加返回值,使用Promise返回

function debounce(fn, delay, immediate = false) {
    //定义定时器,保存上一个
    const timer = null
    const isDone = false

    //真正执行函数
    const doDebounce = function (...args) {
        //添加一个Promise对象
        return new Promise((resolve, reject) => {
            //清除上一个定时器
            if (timer) clearTimeout(timer)

            //是否立即执行
            if (immediate && !isDone) {
                //使用Promise的成功回调将其返回
                const result = fn.apply(this, args)
                if (result) resolve(resolve)
                isDone = true
            }
            else {
                //延迟执行
                timer = setTimeout(() => {
                    //调用Promise的失败回调返回结果
                    const result = fn.apply(this, args)
                    if (result) reject(result)
                }, delay)
            }

        })
    }
    //取消,由于函数也可作为对象使用,故添加一个重置函数
    doDebounce.cancel = function () {
        if (timer) clearTimeout(timer)
        timer = null
        isDone = false
    }
    return doDebounce
}



 

posted @ 2022-10-28 22:24  新时代的搬砖人  阅读(337)  评论(0)    收藏  举报