JavaScript 防抖、节流、深拷贝、事件总线 —— 节流函数

102 阅读4分钟

JavaScript 防抖、节流、深拷贝、事件总线 —— 节流函数

认识节流函数(throttle)

节流和防抖的区别

  • 防抖实现的是我们的将一个事件实现延迟的执行的一种操作模式
  • 但是我们的节流是实现的是我们的在相同的时间内控制我们的实际的操作的次数

节流的基本实现的需求

  • 当我们的事件触发的时候,会执行这个事件的响应函数
  • 如果我们的一个事件会被频繁的触发,那么节流函数的实现的就是控制执行函数的频率
  • 不管是在这个中间发生了多少次的触发该事件,执行函数的频率总是固定的

应用场景

  • 监听页面的滚动实现的节流
  • 鼠标的移动事件的节流
  • 用户频繁点击按钮的操作
  • 游戏设计的时候实现使用我们的节流

节流函数版本一

function My_throttle(callback, interval = 3000) {
    let start_time = 0
    const _throttle = function (...args) {
        const now_time = new Date().getTime()
        const wait_time = interval - (now_time - start_time)
​
        if (wait_time <= 0) {
            callback.apply(this, args)
            start_time = now_time
        }
    }
​
    return _throttle
}
​
​
const throttle = My_throttle(function() {
    console.log("我被执行了", this)
})
​
while(true) {
    throttle()
}

代码解读

  • 首先我们实现的这样的限制相同的时间内进行限制函数的运行次数,我们的最终运行的实际上是在时间戳等于设置的间隔时间

    • 的时候实现运行的
  • start_time 指代的是我们的函数开始执行的时间

    • now_time 指代的是我们的函数的需要执行的时候现在的时间
  • 但是任然具有一定的 bug ,就是函数的是立即执行的,因为第一次获取的时间戳很大很大

节流函数版本二

  • 我们上面的代码是无法实现判断是否需要立即执行的,这个时候我们就可以给一个标识符来决定我们是否立即执行了
function My_throttle(callback, interval = 3000, immediate = true) {
    let start_time = 0
    const _throttle = function (...args) {
        const now_time = new Date().getTime()
        // 开始决定是否需要进行立即执行
        if (immediate === false && start_time === 0) {
            start_time = now_time
        }
        
        const wait_time = interval - (now_time - start_time)
        if (wait_time <= 0) {
            callback.apply(this, args)
            start_time = now_time
        }
    }
    return _throttle
}
​
​
const throttle = My_throttle(function() {
    console.log("我被执行了", this)
})
​
while(true) {
    throttle()
}

同时我们后续是否需要进行判断我们的最后一次是否执行的就是我们的: 再添加一个变量来实现判断最后一次是否执行

节流函数版本三

这个时候我们实现控制最后一次是否执行,就是通过的是我们的 定时器实现的判断是否执行

function My_throttle(callback, interval = 3000, {immediate = true, is_execute = false} = {}) {
    let start_time = 0
    let timer = null
​
    const _throttle = function (...args) {
        const now_time = new Date().getTime()
​
        // 开始决定是否需要进行立即执行
        if (immediate === false && start_time === 0) {
            start_time = now_time
        }
​
        const wait_time = interval - (now_time - start_time)
        if (wait_time <= 0) {
            if (timer) clearTimeout(timer)
            callback.apply(this, args)
            start_time = now_time
            timer = null
            return
        }
​
        // 判断是否需要执行尾部
        if (is_execute && !timer) {
            timer = setTimeout(function () {
                callback.apply(this, args)
                start_time = new Date().getTime()
                timer = null
            }, wait_time)
        }
    }
​
    return _throttle
}
​
​
const throttle = My_throttle(function() {
    console.log("我被执行了", this)
}, 1000, { immediate: false })
​
while(true) {
    throttle()
}

节流函数版本四

版本四就是为了解决我们的返回值的处理的问题

这个时候,我们就可以实现的是我们的使用 Promise 来实现进行解决返回值功能

function My_throttle(callback, interval = 3000, {immediate = true, is_execute = false} = {}) {
    let start_time = 0
    let timer = null
​
    const _throttle = function (...args) {
        return new Promise((resolve, reject) => {
            try {
                const now_time = new Date().getTime()
​
                // 开始决定是否需要进行立即执行
                if (immediate === false && start_time === 0) {
                    start_time = now_time
                }
​
                const wait_time = interval - (now_time - start_time)
                if (wait_time <= 0) {
                    if (timer) clearTimeout(timer)
                    callback.apply(this, args)
                    start_time = now_time
                    timer = null
                    resolve(this)
                    return
                }
​
                // 判断是否需要执行尾部
                if (is_execute && !timer) {
                    timer = setTimeout(function () {
                        callback.apply(this, args)
                        start_time = new Date().getTime()
                        timer = null
                        resolve(this)
                    }, wait_time)
                }
​
            } catch (error) {
                reject(error)
            }
        })
    }
​
    // 开始设置我们取消节流函数执行的参数
    _throttle.cancel = function () {
        if (timer) clearTimeout(timer)
        start_time = 0
        timer = null
    }
​
    return _throttle
}
​
​
const throttle = My_throttle(function() {
    console.log("我被执行了", this)
}, 1000, { immediate: false })
​
while(true) {
    throttle()
}

总结

  • 节流函数就是实现的是在固定的时间内控制一个实现的执行频率,这个就是我们的节流函数的书写
  • 版本一: 就是节流函数的核心实现代码
  • 版本二: 进行添加了我们的用来实现判断是否立即执行的功能
  • 版本三: 进行的就是实现节流函数最后一次是否执行的判断添加
  • 版本四: 就是实现的是我们的通过 Promise 来实现控制返回值结果的实现以及取消节流函数执行的功能添加