Fe-interview: [js] 第115天 分别写出防抖和节流的两个函数,并描述它们分别有什么运用场景?

Created on 8 Aug 2019  ·  12Comments  ·  Source: haizlin/fe-interview

第115天 分别写出防抖和节流的两个函数,并描述它们分别有什么运用场景?

js

Most helpful comment

type Timeout = number // browser
// type Timeout = NodeJS.Timeout // node

/**
 * 防抖:生成一个函数,它在被调用后会等待一段时间再执行。
 * 如果在等待期间再次调用,之前还未执行的调用会被取消。
 * @param fn 要防抖的函数
 * @param timeout 超时时间
 */
function debounce(fn: (...args: any[]) => any, timeout: number) {
    let time: Timeout = null
    return function _debounced(...args: any[]) {
        if (time !== null)
            { clearTimeout(time) }
        time = setTimeout(() => {
            fn(...args)
            time = null
        }, timeout)
    }
}

/**
 * 节流:生成一个函数,它在被调用后一段时间内再次被调用不起作用。
 * @param fn 要节流的函数
 * @param timeout 超时时间
 */
function throttle(fn: (...args: any[]) => any, timeout: number) {
    let time: Timeout = null
    return function _throttled(...args: any[]) {
        if (time === null) {
            fn(...args)
            time = setTimeout(() => time = null, timeout)
        }
    }
}

防止用户高频操作导致事件处理器处理不来。

All 12 comments

type Timeout = number // browser
// type Timeout = NodeJS.Timeout // node

/**
 * 防抖:生成一个函数,它在被调用后会等待一段时间再执行。
 * 如果在等待期间再次调用,之前还未执行的调用会被取消。
 * @param fn 要防抖的函数
 * @param timeout 超时时间
 */
function debounce(fn: (...args: any[]) => any, timeout: number) {
    let time: Timeout = null
    return function _debounced(...args: any[]) {
        if (time !== null)
            { clearTimeout(time) }
        time = setTimeout(() => {
            fn(...args)
            time = null
        }, timeout)
    }
}

/**
 * 节流:生成一个函数,它在被调用后一段时间内再次被调用不起作用。
 * @param fn 要节流的函数
 * @param timeout 超时时间
 */
function throttle(fn: (...args: any[]) => any, timeout: number) {
    let time: Timeout = null
    return function _throttled(...args: any[]) {
        if (time === null) {
            fn(...args)
            time = setTimeout(() => time = null, timeout)
        }
    }
}

防止用户高频操作导致事件处理器处理不来。

节流:规定在一个单位时间内,只能触发一次函数。
防抖:在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。

/**
* 节流
*/
let throttling = () => {
    let e = true
    return event = () => {
        if (e) {
            e = false
            setTimeout(function () { e = true, console.log(1) }, 5000)
        }
    }
}
/**
 * 防抖 
 */
let antiShake = () => {
    let e = true
    return event = () => {
        if (!e) {
            { clearTimeout(time) }
        } 
        e = false
        time = setTimeout(function () { e = true, console.log(1) }, 5000)
    }
}

看看楼上带佬代码,看看自己代码,啊!我真菜。

    function throttle(func, wait) {
      let time = 0;
      return function () {
        let context = this;
        let args = arguments
        let now = Date.now()
        if (now - pre > wait) {
          //一定时间间隔只执行一次,第一次执行的时间戳差必定大于wait
          fun.apply(context, args)
          time = Date.now();
        }
      }
    }
    // 防抖
    function debounce(fun, wait) {
      let timeout;
      return function () {
        let context = this;
        let args = arguments;
        if (timeout) {
          clearTimeout(timeout)
        }
        timeout = setTimeout(() => {
          fun.apply(context, args)
        }, wait)
      }
    }

```.javascript
/**

  • 防抖
  • @param {Func} callback 需要防抖的函数
  • @param {Number} wait 等待毫秒数
    */
    function debounce(callback, wait = 0) {
    let timer = null
    return function () {
    if (timer) {
    clearTimeout(timer)
    }
    timer = setTimeout(() => {
    callback.apply(this, arguments)
    }, wait)
    }
    }

/**

  • 节流
  • @param {Func} callback 需要节流的函数
  • @param {Number} wait 等待毫秒数
    */
    function throttle(callback, wait = 0) {
    let lastTime = null
    let nowTime = null
    return function () {
    nowTIme = Date.now()
    if (!lastTime || lastTime - nowTime > wait) {
    callback.apply(this, arguments)
    lastTime = nowTime
    }
    }
    }
    ```
   // 节流: 在操作的一段时间内,函数执行的频率是固定的(定时器形式)
    function throttle(foo, hz_ms) {
      return function () {
        const ctx = this;
        const args = arguments;
        if (!throttle.id) {
          throttle.id = setTimeout(() => {
            foo.apply(ctx, args)
            throttle.id = null;
          }, hz_ms);
        }
      }
    }
    // 防抖: 频繁的操作完成之后,再执行对应的函数;
    function debounce(foo, lay_ms) {
      return function () {
        clearTimeout(debounce.id);
        const that = this;
        const args = arguments;
        debounce.id = setTimeout(() => {
          foo.apply(that, args);
        }, lay_ms);
      }
    }

    function handler() {
      console.log(111);
    }
    // document.onmousemove = debounce(handler, 1000)
    document.onmousemove = throttle(handler, 1000)

节流:规定在一个单位时间内,只能触发一次函数。
防抖:在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。

/**
* 节流
*/
let throttling = () => {
    let e = true
    return event = () => {
        if (e) {
            e = false
            setTimeout(function () { e = true, console.log(1) }, 5000)
        }
    }
}
/**
 * 防抖 
 */
let antiShake = () => {
    let e = true
    return event = () => {
        if (!e) {
            { clearTimeout(time) }
        } 
        e = false
        time = setTimeout(function () { e = true, console.log(1) }, 5000)
    }
}

看看楼上带佬代码,看看自己代码,啊!我真菜。

你的可读性比较好,这也是代码的优点之一

节流(throttle)

throttle函数的目的很简单,就是在一段时间内相同的事件只处理一次,避免过快过多的执行造成程序占用内存过大而导致卡顿;实现的方式主要有两种:

  1. 时间戳:
function throttle(fn, delay) {
  let last = 0 // 这样能保证第一次触发能够立即被执行
  return function throttle_fn() {
    if(Date.now() - last >= delay) {
      fn.apply(this, arguments)
      last = Date.now()
    }
  }
}

主要是记录上一次执行的时间戳,然后与当前时间戳进行比较,若超过指定的时间则执行一次;

  1. 计时器:
function throttle2(fn, delay) {
  let last = null
  return function throttle_fn() {
    if(last === null) {
      last = setTimeout(() => {
        fn.apply(this, arguments)
        last = null // 清除已执行的计时器标记
      }, delay)
    }
  }
}

该方法主要利用计数器的标记进行节流,计时器在执行完一次操作之前标记不会被处理,因此在规定时间内的其它操作都不会被执行,从而达到了规定时间内只执行一次的目的。

防抖(debounce)

debounce函数的目的是为了避免相同的事件触发的频率过快,即连续两次事件触发的执行时间之差不能低于某个限定值,相当于控制了事件执行的频率。

可以利用计时器延迟事件的执行来实现:

function debounce(fn, delay) {
  let last = null
  return function debounce_fn() {
    if(last) {
      clearTimeout(last) // 若此时距离上次执行的时间小于delay,就相当于取消了前一次执行
    }
    last = setTimeout(() => {
      fn.apply(this, arguments)
    }, delay) // 事件延迟执行,只有当后一次触发与当前触发≥delay时才会被执行!
  }
}

由于每次触发都会执行clearTimeout,因此若前一次延迟操作没有被执行则会被自动取消,即前一次触发与后一次触发间隔时间小于规定间隔时间时前一次触发会被自动取消执行;

在我看来,防抖与节流都是控制函数调用频率的手段。两者的主要的区别是:在给定时间间隔内调用多次时,防抖采用最新调用而节流采用首次调用

节流没必要用定时器,我被面试官问到过

防抖函数 限定多少时间只能执行一次 执行多次取最后一次执行

function success(e) {
    console.log("提交成功");
}

const debounce = (fn, delay) => {
    let timer = null
    return (...args) => { 
        clearTimeout(timer); 
        timer = setTimeout(() => {
            fn.apply(this, args) 
        },delay);
    }
}
const oDebounce = debounce(success, 1000) 
let btn = document.getElementById('btn')
btn.addEventListener('click', oDebounce)

节流就是在一段时间内相同的事件只处理一次

function success(e) {
    console.log("提交成功");
}

// 函数节流
const throttle = (fn, delay) => { 
    let flag = true 
    return (...args) => { 
        if (!flag) {
            return
        }
        flag = false 
        setTimeout(() => { 
            fn.apply(this, args)
            flag = true
        }, delay);
    }
}

const oThrottle = throttle(success, 2000) 

let btn = document.getElementById('btn')
btn.addEventListener('click', oThrottle)

节流函数

function throttle(fn, interval = 200){
  let canrun = true;
  if(!canrun)return;
  canrun = false;
  setTimeout(()=>{
    fn.apply(this,arguments);
    canrun = true;
  }, interval);
};

防抖函数

function debounce(fn,intercal=200){
  let timeout = null;
  if(timeout){
    clearTimeout(timeout);
  }
  timeout = setTimeout(()=>{
    fn.apply(this,arguments)
  },interval);
};
/**
     * 节流函数
     * */
    function throttle(fn, delay, scope) {
        let timer;
        return function () {
            let context = scope || this, args = arguments;
            if (!timer) {
                timer = setTimeout(() => {
                    fn.apply(context, args);
                    timer = null;
                }, delay)
            }
        }
    }

    /**
     * 防抖函数
     * */
    function debounce(fn, delay, scope) {
        let timer;
        return function () {
            let context = scope || this, args = arguments;
            clearTimeout(timer);
            timer = setTimeout(() => {
                fn.apply(context, args);
            }, delay)
        }
    }
Was this page helpful?
0 / 5 - 0 ratings