Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
haizhilin2013 opened this issue Aug 8, 2019 · 13 comments
Labels
js JavaScript

Comments

@haizhilin2013
Copy link
Collaborator

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

@haizhilin2013 haizhilin2013 added the js JavaScript label Aug 8, 2019
@ghost
Copy link

ghost commented Aug 9, 2019

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)
        }
    }
}

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

@NicholasBaiYa
Copy link

NicholasBaiYa commented Aug 9, 2019

节流:规定在一个单位时间内,只能触发一次函数。
防抖:在事件被触发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)
    }
}

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

@LinStan
Copy link

LinStan commented Aug 9, 2019

    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)
      }
    }

@bertcai
Copy link

bertcai commented Aug 9, 2019

/**
 * 防抖
 * @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
        }
    }
}

@nowherebutup
Copy link

   // 节流: 在操作的一段时间内,函数执行的频率是固定的(定时器形式)
    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)

@nowherebutup
Copy link

节流:规定在一个单位时间内,只能触发一次函数。
防抖:在事件被触发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)
    }
}

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

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

@xxf1996
Copy link

xxf1996 commented Aug 9, 2019

节流(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,因此若前一次延迟操作没有被执行则会被自动取消,即前一次触发与后一次触发间隔时间小于规定间隔时间时前一次触发会被自动取消执行;

@EmiyaYang
Copy link

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

@bowencool
Copy link

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

@wsylws
Copy link

wsylws commented Nov 11, 2019

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

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)

@WangHngLeee
Copy link

WangHngLeee commented Jul 1, 2020

节流函数

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);
};

@wepn13232
Copy link

/**
	 * 节流函数
	 * */
	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)
		}
	}

@xiaoqiangz
Copy link

/**

  • 防抖 N秒内函数只执行一次,如果N秒内再次触发,会重新计算时间。
  • @param {*} time
    */
    function debounce(time, fn) {
    let timed = null
    return function(args) {
    if (timed) clearTimeout(timed)
    timed = setTimeout(()=> {
    fn(args)
    timed = null
    }, time)
    }
    }

/**

  • N秒内函数只执行一次,如果再次触发需要等待先前的函数执行完毕
  • @param {} time
  • @param {*} fn
    */
    function throttle(time, fn) {
    let timed = null
    return function(args) {
    if (timed){
    return false
    }
    timed = setTimeout(()=>{
    fn(args)
    timed = null
    }, time)
    }
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
js JavaScript
Projects
None yet
Development

No branches or pull requests