阅读 3311

JS的防抖、节流函数

防抖、节流函数一般应用在一些高频触发的方法,例如搜索框联想输入的input事件、onmousemove事件、click事件等等;实际上业务不需要多次触发,那么就需要用到防抖或者节流来处理啦。

简单的可以这样理解

防抖函数:疯狂点击按钮,每次点击的时间间隔都小于规定时间,那么相应的方法不会执行

节流函数:疯狂点击按钮,规定的时间间隔内只触发一次相应的方法

是否立即执行的区别就是,立即执行执行的是第一次触发的状态,非立即执行触发的是最后一次的状态

防抖

代码

 let Debounce = function (fn, delay = 300, immediate = false) {
    let timer = null // 闭包存储setTimeout状态
    return function () {
        let self = this // 事件源this
        let args = arguments // 接收事件源的event
        if (timer) clearTimeout(timer) // 存在就清除执行fn的定时器
        if (immediate) { // 立即执行
            let callNow = !timer // 执行fn的状态
            timer = setTimeout(function () {
                timer = null
            }, delay)
            if (callNow) fn.apply(self, args)
        } else { // 非立即执行
            timer = setTimeout(function () { // 或者使用箭头函数将this指向dom
                fn.apply(self, args)
            }, delay)
        }
    }
}

let con1 = document.querySelector('.con1')
let con2 = document.querySelector('.con2')
let con3 = document.querySelector('.con3')

let addNum = function (args) {
    console.log(this, args)
    this.innerText = (+this.innerText) + 1
}

con1.onmousemove = addNum // 无防抖

con2.onmousemove = Debounce(addNum) // 防抖

con3.onmousemove = Debounce(addNum, 300, true) // 防抖(立即执行)
复制代码

效果对比

节流

代码

// 基础版节流
let Throttle = function (fn, delay = 500) {
    let flag = true
    return function () {
        let self = this
        let args = [...arguments]
        if (!flag) return
        flag = false
        setTimeout(function () {
            fn.apply(self, args)
            flag = true
        }, delay)
    }
}

let con1 = document.querySelector('.con1')
let con2 = document.querySelector('.con2')

let addNum = function (args) {
    console.log(this, args)
    this.innerText = (+this.innerText) + 1
}

con1.onmousemove = addNum // 无节流

con2.onmousemove = Throttle(addNum, 1000) // 节流
复制代码

效果对比

节流函数的另一种写法,防抖函数也可以使用时间戳作为判断条件

// 时间间隔作为判断
let ThrottleTime = function (fn, delay = 500) {
    let preTime = 0 // 记录上一次执行时间
    return function () {
        let self = this, // 保留执行时候的的this
            args = [...arguments], // 执行时候的传入参数
            nowTime = +new Date() // 记录当前的时间
        if (nowTime - preTime >= delay) {
            preTime = nowTime // 更新执行时间
            fn.apply(self, args)
        }
    }
}
复制代码

加上立即执行状态

// 是否立即执行
let ThrottlePro = function (fn, delay = 500, immediate = false) {
    let preTime = 0 // 记录上一次执行时间
    return function () {
        let self = this, // 保留执行时候的的this
            args = [...arguments], // 执行时候的传入参数
            nowTime = +new Date(), // 记录当前的时间
            flag = nowTime - preTime >= delay // 执行命令
        if (immediate) { // 是否立即执行
            if (!flag) return
            preTime = nowTime // 更新执行时间
            fn.apply(self, args)
        } else {
            if (!flag) return // 不满足执行条件
            preTime = nowTime
            setTimeout(function () {
                fn.apply(self, args)
            }, delay)
        }
    }
}
复制代码

相关链接:

八步开发一个vue的组件库

JS常用的深、浅拷贝

VUE的实现原理(数据劫持、观察者模式)

Javascript实现简单的冒泡排序、插入排序

一个非常简单的-发布订阅模式

文章分类
前端
文章标签