咱们常常会绑定一些继续触发的事件,比方resize、scroll、mousemove等等,如果事件调用无限度,会减轻浏览器累赘,导致用户体验差,咱们能够应用debounce(防抖)和throttle(节流)的形式来缩小频繁的调用,同时也不会影响理论的成果。

防抖的概念

触发事件后n秒后才执行函数,如果在n秒内触发了事件,则会从新计算函数执行工夫
防抖函数能够分为立刻执行,和非立刻执行两个版本
非立刻执行版本

  • 非立刻执行版本
function debounce(fn, wait) {    let timer = null    return function () {        const context = this        const args = arguments        timer && clearTimeout(timer)        timer = setTimeout(() => {            fn.apply(context, args)           }, wait)    }}

此函数一开始不会马上执行,而是等到用户操作完结之后期待wait秒后才执行,如果在wait之内用户又触发了事件,则会从新计算

  • 立刻执行版本
function debounce(fn, wait) {    let timer = null    return function () {        const args = arguments        const now = !timer        timer && clearTimeout(timer)        timer = setTimeout(() => {            timer = null        }, wait)        if (now) {            fn.apply(this, args)        }    }}

立刻执行就是触发事件后马上先执行一次,直到用户进行执行事件期待wait秒后再执行一次

咱们能够将两种版本合并成一种

/** * @desc 函数防抖 * @param fn 函数 * @param wait 提早执行毫秒数 * @param immediate true 表立刻执行,false 示意非立刻执行 */ function debounce(fn, wait, immediate) {    let timer = null    return function () {        const context = this        const args = arguments        timer && clearTimeout(timer)        if (immediate) {            const now = !timer            timer = setTimeout(() => {                timer = null            }, wait)            now && fn.apply(context, args)        } else {            timer = setTimeout(() => {                fn.apply(context, args)            }, wait)        }    } }

节流的概念

间断触发事件但在n秒内只执行一次函数
对于节流有工夫戳和定时器两种版本

  • 工夫戳版本
function throttle(fn, wait) {    var prev = 0    return function () {        let now = Date.now()        let context = this        let args = arguments        if (now - prev > wait) {            fn.apply(context, args)            prev = now        }    }}

在继续触发事件的过程中,函数会立刻执行,用户在wait秒内不论执行多少次事件,都会期待wait秒后再执行。

  • 定时器版本
function throttle(fn, wait) {    var timer = null    return function () {        const context = this        const args = arguments        if (!timer) {            timer = setTimeout(() => {                timer = null                fn.apply(context, args)            }, wait)        }    }}

在触发事件的过程中,不会立刻执行,并且每wait秒执行一次,在进行触发事件后还会再执行一次。

工夫戳版的函数触发是在时间段内开始的时候,而定时器版的函数触发是在时间段内完结的时候。

将两种形式合并

/** * @desc 函数节流 * @param fn 函数 * @param wait 提早执行毫秒数 * @param type 1 表工夫戳版,2 表定时器版 */ function throttle(fn, wait, type) {    if (type === 1) {        var prev = 0    } else {        var timer = null    }     return function() {        const context = this        const args = arguments         if (type === 2) {             if (!timer) {                 timer = setTimeout(() => {                   timer = null                   fn.apply(context, args)                  }, wait)             }         } else if(type === 1) {            const now = Date.now()            if (now - prev > wait) {                fn.apply(context, args)                prev = now            }         }     } }

参考链接