在实际的开发中,我们通常会期望在首次和末次都执行一次,这时候我们就需要将节流和防抖结合起来。
throttleAndDebounce
function throttleAndDebounce(fn: () => void, delay: number) {let timeout: numberlet called: booleanlet ctx: anyreturn function(...args: []) {ctx = thisif (timeout) {clearTimeout(timeout)}if (!called) {fn.apply(ctx, args)called = truetimeout = setTimeout(() => {called = false}, delay)} else {timeout = setTimeout(() => fn.apply(ctx, args), delay)}}}
为了实现对应的效果,我们需要使用闭包来保存两个参数,定时器的 timeoutid 和当前的执行状态 called。当执行函数的时候,每次都会检查是否存在 timeoutid,若存在则将其清理掉。然后再判断当前的执行状态,当在当前周期内执行过一次之后就将 called置为 true,并生成一个计时器,在特定时间之后再将其重置为 false。若在某个时间停止执行之后,还会保留一个计时器,即 16 行所写,这样就会在最后一次触发特定时间之后完成最后的触发操作。
debounce
防抖是指对持续触发的函数进行延迟执行,当触发之后间隔一点时间没有触发时函数才会执行一次。因为这样的特性,通常情况下第一次触发不会直接执行,而最后一次触发会在间隔一定时间之后进行执行。
function debounce(fn: () => void, delay: number) {let timeout: numberreturn function (...args) {const ctx = thisclearTimeout(timeout)timeout = setTimeout(() => {fn.apply(ctx, args)})}}
function debounce(fn: Function, wait: number, immediate: boolean) {let timeoutreturn function (...args: any[]) {const ctx = thisconst callNow = immediate && !timeoutconst later = function () {timeout = nullif (!immediate) fn.apply(ctx, args)}clearTimeout(timeout)timeout = setTimeout(later, wait)if (callNow) fn.apply(ctx, args)}}
函数会在第一次触发的时候执行,间隔一定时间之后,再次触发也是最后先执行。
throttle
节流是当函数不断进行触发的时候,只有在经过特定的时间间隔才会执行一次。
function throttle(fn: () => void, delay: number) {let lastTime = 0return function (...args) {let now = +new Date()if (now - lastTime > delay) {lastTime = nowfn.apply(this, args)}}}
function throttle(fn: Function, delay: number) {let timerId = nullreturn function (...args) {const ctx = thisif (!timerId) {timerId = setTimeout(() => {timerId = nullfn.apply(ctx, args)}, delay)}}}
节流是第一次就会触发,然后再在固定时间内触发一次,当停止之后最后一次也不会触发。
