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

防抖(debounce)函数的作用是什么?有哪些应用场景,请实现一个防抖函数。 #10

Open
YvetteLau opened this issue May 24, 2019 · 49 comments

Comments

@YvetteLau
Copy link
Owner

No description provided.

@AILINGANGEL
Copy link

做一个类比,假设你和你的朋友chatty通过微信聊天,她非常的健谈,那么你有如下几种方式来处理她的消息:

  • 最基本的就是时不时就看微信,这样会很浪费时间,但获取信息的实时性很高
  • 函数节流: 每隔5分钟查看一次,这样获取信息的实时性不高,但是不会耽误你获取信息
  • 函数防抖:假设她把她的故事分成了好几段发给你,你假定在5分钟内她没有再发信息就是整个故事已经发完了,然后再去查看。(函数防抖的非立即执行版)

在浏览器中,有很多事件比如window的onresize 鼠标的mousemove 以及滚轮事件wheel等,他们触发的很频繁,这个时候函数没必要一直执行。函数防抖就是让事件触发的n秒内只执行一次,如果连续触发就重新计算时间.

function debounce(fn, delay, immediate) {
    let timer = null;
    return function() {
        clearTimeout(timer); //重新计算时间
        let context = this;
        let args = arguments;
        if (!timer && immediate) {
            fn.apply(context, args);
        }
        timer = setTimeout(function() {
            if (!immediate) {
                fn.apply(context, args);
            } else {
                timer = null;
            }
        }, delay)
    }
}

@tpxiang
Copy link

tpxiang commented May 24, 2019

防抖(debounce)在n秒内函数只被执行一次,如果在这个时间内再次被触发,则需要再次计算时间。
应用场景:
1、文本输入框的验证,输入完成之后验证一次即可,不需要每次都发请求验证。
2、size/scroll的触发统计事件。
实现:

function debounce(fn, delay, immediate) {
      let timer = null;
      return function() {
      const context = this;
      const args = arguments;
      let result = undefined;
      timer && clearTimeout(timer);
 
      if (immediate) {
        const doNow = !timer;
  
        timer = setTimeout(() => {
          timer = null;
        }, delay);
        if (doNow) {
          result = fn.apply(context, args);
        }
      }
      else {
        timer = setTimeout(() => {
          fn.apply(context, args);
        }, delay);
      }
      return result;
    };
 }

@xiatiandenixi
Copy link

xiatiandenixi commented May 24, 2019

在频繁触发某些事件,导致大量的计算或者非常消耗资源的操作的时候,防抖可以强制在一段连续的时间内只执行一次。

function debounce(fn, delay) {
	let timer = null
	return function() {
		clearTimeout(timer)
		let context = this
		let args = arguments
		timer = setTimeout(() => {
			fn.apply(context, args)
		}, delay)
	}
}

@jizx
Copy link

jizx commented May 24, 2019

在一定的时间间隔内只执行一次,如果重新触发则重新计算时间间隔。常见的场景如,远程搜索输入框、浏览器resize、scroll等,主要为了节约服务器性能。
function debounce(fn,delay){ let timer = null; return function(){ clearTimeout(timer); let args = arguments; let context = this; timer = setTimeout(()=>{ fn.apply(context,args)},delay) } }

@taoyaoyaoa
Copy link

防抖函数为了防止函数多次调用

const debounce = function (func,wait = 50) {
// 缓存一个定时器id
let timer = null;
// 这里返回的函数时每次用户实际调用的防抖函数
// 如果已经设定过定时器了就清空上一次的定时器
// 开始一个定时器,延迟执行用户传入的方法
return function(...args){
if(timer) clearTimeout(timer);
timer = setTimeout(()=>{
//将实际的this和参数传入用户实际调用的函数
func.apply(this,args);
},wait);
}
};
今天的题还是不会,参考了其他博客,感谢小姐姐 ,会努力学习跟大家一起进步~

@Talljack
Copy link

防抖函数常用来进行处理某些频繁触发的请求事件,如input搜索事件,如果用户每输入一个字都发送一次请求那么则会非常耗费性能,所以用防抖函数进行限制,在一定时间内触发的事件只有到了指定的时间才发送一次请求。
var debounce = function(fn, delay = 100) {
let timer = null;
return function(...arg) {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
fn.apply(this, arg)
}, delay)
}
}

@Webxiaoyaun
Copy link

函数防抖
常用就是高频率触发一个函数时候,比如滚动条事件,窗口收缩,模糊搜索,每次滚动或者输入时候,都会触发函数执行,这样体验和性能都不好,防抖主要对性能优化,减少服务器负担

function throttle(func, wait) {
    let timeout;
    return function() {
        let context = this;
        let args = arguments;
        if (!timeout) {
            timeout = setTimeout(() => {
                timeout = null;
                func.apply(context, args)
            }, wait)
        }

    }
}

@muyiweibo
Copy link

防抖用于频繁操作的情况,比如输入关键字匹配下拉列表,由于输入是连续的因此为了提高性能,在一定时间内输入则采用防抖延迟请求时间
var timer = null
function debounce(){
clearTimeout(timer)
timer = setTimeout(function(){
console.log(1)
}, 1000)
}

@yelin1994
Copy link

防抖体会最深的,应该是下拉框的远程模糊搜索,不做防抖的话,每次用户输入变化,都立即请求服务器,对服务器负担太大。
function parent () {
let timer =null ;
return son () {
clearTimeout(timer);
timer = setTimeout(() => {
// 请求
}, 300) // 这边设300ms的延迟
}

@CCZX
Copy link

CCZX commented May 24, 2019

防抖函数的作用是限制用户的频繁操作,影响网页的性能,防抖函数的原理是如果用户频繁操作事件处理函数就不会执行,只有当进行了最后一次操作,并且时间大于设定的时间才会执行;防抖函数的应用十分广泛:比如:1.只有在用户最后一次改变页面尺寸时才做一些操作,2:当用户在搜索框停止输入后发起Ajax请求;

function debounce(fn, wait, immediate = false) {
  let timer = null
  return function(...arg){
    if(immediate) {
      fn.apply(this,arg)
      immetiate = false
    }
    timer ? clearTimout(timer) : ""
    timer = setTimeout(()=>{
      fn.apply(this.arg)
    },wait)
  }
}

@darlingyz
Copy link

防抖函数概念作用:
  函数防抖(debounce)是指在一定时间内,在动作被连续频繁触发的情况下,动作只会被执行一次,也就是说当调用动作过n毫秒后,才会执行该动作,若在这n毫秒内又调用此动作则将重新计算执行时间,所以短时间内的连续动作永远只会触发一次,比如说用手指一直按住一个弹簧,它将不会弹起直到你松手为止。
	目的:为了限制函数执行频率,优化函数触发频率过高导致的响应速度跟不上触发频率,出现延迟或者卡死的现象
防抖就是防止频繁的调用函数 

应用场景:

window对象的resize,scroll事件。
拖拽的mousemove,mousedown事件。
文字输入,keyup、keydown事件。
加载更多.
实现一个防抖函数
function debounce(func, wait, immediate) {
var timeout, result;
var debounced = function () {
var context = this;
var args = arguments;
if (timeout) clearTimeout(timeout);
if (immediate) {
// 如果已经执行过,不再执行
var callNow = !timeout;
timeout = setTimeout(function(){
timeout = null;
}, wait)
if (callNow) result = func.apply(context, args)
}
else {
timeout = setTimeout(function(){
func.apply(context, args)
}, wait);
}
return result;
};
debounced.cancel = function() {
clearTimeout(timeout);
timeout = null;
};
return debounced;
}
d
----嘤嘤嘤,不怎么会实现,只知道概念,期待小姐姐的怎么实现的

@MissWXiang
Copy link

1.防抖函数作用和应用场景:
函数防抖是指对于在事件被触发n秒后再执行的回调,如果在这n秒内又重新被触发,则重新开始计时,是常见的优化,适用于
(1)表单组件输入内容验证
(2)防止多次点击导致表单多次提交等情况,防止函数过于频繁的不必要的调用。
2.防抖函数:
function debounce(func, wait, immediate) {
let time
let debounced = function() {
let context = this
if(time) clearTimeout(time)

    if(immediate) {
        let callNow = !time
        if(callNow) func.apply(context, arguments)
        time = setTimeout(
            ()=>{time = null} //见注解
        , wait)
    } else {
        time = setTimeout(
            ()=>{func.apply(context, arguments)}
        , wait) 
    }
}
return debounced

}
(微信名:RUN)

@TTTTTTTZL
Copy link

防抖函数(debounce):
含义:触发事件后在n秒之内只触发函数一次,如果在n秒事件内再次触发事件,则n归零,重新计算时间。
应用场景:input输入框输入信息请求后台数据,若输入一个字便请求一次服务器,会增加服务器压力,耗费性能。频繁点赞取消点赞、window触发resize、手机或邮箱的验证等。
目的:限制函数触发频率;
实现核心:维护一个setTimeout,在冷却时间内再次触发函数则清空原setTimeout重新计算一个setTimeout推入队列等待执行。

function debounce(func,wait){
    var timeout;
    return function(){
        var context = this;
        var args = arguments;

        clearTimeout(timeout)
        timeout = setTimeout(function(){
            func.apply(context,args);
        },wait)

    }
}

@MissNanLan
Copy link

MissNanLan commented May 24, 2019

在日常工作中,有三种场景我使用了防抖
比如搜索框change时查询接口、scroll、resize事件被触发

什么是防抖

所谓防抖,就是指触发事件后在n秒内只能执行一次,如果在n秒内触发事件的,则会重新计算函数执行事件

防抖的两种状态

立即执行和非立即执行
非立即执行
触发事件后函数不会立即执行,而是在n后开始执行

<body>
    <div id="content"
        style="height:1000px;line-height: 1000px;text-align:center; color: #fff;background-color:#ccc;font-size:80px;">
        1
    </div>
    <script>
        // 非立即执行版
        function debounce(func, wait) {
            let timeout
            return function () {
                let context = this;
                let args = arguments;
                console.log(context, args);
                if (timeout) clearTimeout(timeout);
                timeout = setTimeout(() => {
                    func.apply(context, args);
                }, wait)
            }
        }

        let num = 1;
        let content = document.getElementById('content');

        function count() {
            content.innerHTML = num++;
        }
        window.addEventListener("scroll", debounce(count,1000));

    </script>

</body>

立即执行
触发事件后函数立即执行

 function debounce(func,wait){
   let timeput;
   return function(){
    let context = this;
    let args = arguments;
     if(timeout){
        clearTimeout(timeout)
    }
    let callNow = !timeout;
   timeout = setTimout(() =>{
       timeout = null
   },wait)
   if(callNow) func,apply(context,args)
  }
  }

@Timoeser
Copy link

防抖意思懂,函数吧,就写不来了,看了别人写的,稍微懂了点
function throttle(func, wait) {
let timeout;
return function() {
let context = this;
let args = arguments;
if (!timeout) {
timeout = setTimeout(() => {
timeout = null;
func.apply(context, args)
}, wait)
}
}
}

@dashengzi66
Copy link

函数防抖
常用就是高频率触发一个函数时候,比如滚动条事件,窗口收缩,模糊搜索,每次滚动或者输入时候,都会触发函数执行,这样体验和性能都不好,防抖主要对性能优化,减少服务器负担
function debounce(func,wait){
var timeout;
return function(){
var context = this;
var args = arguments;

    clearTimeout(timeout)
    timeout = setTimeout(function(){
        func.apply(context,args);
    },wait)

}

}

@wangzhijun-github
Copy link

防抖简单来说就是一段时间内只触发一次,跟节流很像(隔一段时间执行一次)
防抖多数是用来高频率触发,但是每一次触发又不是必须要处理的情况,比如input的onchanage、document的onscroll,window的onresize。
function debounce(fn, time){
var timer = null;
return function(){
timer ? clearTimeout(timer) : null;
timer = setTimeout(()=> fn(),time);
}
}

@proYang
Copy link

proYang commented May 24, 2019

关于 debounce 和 throttling 的区别,推荐一篇文章吧

image

https://css-tricks.com/debouncing-throttling-explained-examples/

@YvetteLau
Copy link
Owner Author

关于 debounce 和 throttling 的区别,推荐一篇文章吧

image

https://css-tricks.com/debouncing-throttling-explained-examples/

谢谢给大家推荐好文,但是也别忘了好好阅读一下哈~

@YvetteLau
Copy link
Owner Author

防抖函数为了防止函数多次调用

const debounce = function (func,wait = 50) {
// 缓存一个定时器id
let timer = null;
// 这里返回的函数时每次用户实际调用的防抖函数
// 如果已经设定过定时器了就清空上一次的定时器
// 开始一个定时器,延迟执行用户传入的方法
return function(...args){
if(timer) clearTimeout(timer);
timer = setTimeout(()=>{
//将实际的this和参数传入用户实际调用的函数
func.apply(this,args);
},wait);
}
};
今天的题还是不会,参考了其他博客,感谢小姐姐 ,会努力学习跟大家一起进步~

今日又比昨天进步了,这一点就已经超级赞了~
一起努力每天进步一点点

@lqzo
Copy link

lqzo commented May 24, 2019

函数防抖:任务频繁触发的情况下,只有任务触发的间隔超过指定间隔的时候,任务才会执行。

应用场景:
楼上 @wangzhijun-github 同学总结的挺好的。防抖多数是用来高频率触发,但是每一次触发又不是必须要处理的情况,比如input的onchanage、document的onscroll,window的onresize,还有onmousemove。当然有些情况节流函数也可以达到节省资源的效果。


  • 输入框键入
    以用户注册时,验证用户名是否被占用为例,如今很多网站为了提高用户体验,不会在输入框失去焦点的时候再去判断用户名是否被占用,而是在输入的时候就在判断这个用户名是否已被注册,但每次输入都会像服务端发送请求,毫无疑问是没有意义的,实际上在用户停止键入时进行查询更为合理。
// 每次输入都发生请求
$('input.user-name').on('input', function () {
  $.ajax({
    url: `https://just.com/check`,
    method: 'post',
    data: {
      username: $(this).val(),
    },
    success(data) {
      if (data.isRegistered) {
        $('.tips').text('该用户名已被注册!');
      } else {
        $('.tips').text('恭喜!该用户名还未被注册!');
      }
    },
    error(error) {
      console.log(error);
    },
  });
});

未优化效果图:
every

// 添加防抖函数
function debounce(fn, interval = 300) {
  let timeout = null;
  return function () {
    clearTimeout(timeout);
    timeout = setTimeout(() => {
      fn.apply(this, arguments);
    }, interval);
  };
}
$('input.user-name').on('input', debounce(function () {
  $.ajax({
    url: `https://just.com/check`,
    method: 'post',
    data: {
      username: $(this).val(),
    },
    success(data) {
      if (data.isRegistered) {
        $('.tips').text('该用户名已被注册!');
      } else {
        $('.tips').text('恭喜!该用户名还未被注册!');
      }
    },
    error(error) {
      console.log(error);
    },
  });
}));

防抖函数效果图:
debounce

JavaScript函数节流与函数防抖


今日答题完成,感谢小姐姐带我们成长

@ccvaille
Copy link

ccvaille commented May 24, 2019

  • mouseover 、scroll 、resize、keyup 事件会频繁触发,会导致页面卡顿,所以希望多次触发的相同事件触发合并成一次触发
  • 作用: 在某段连续时间内,在事件触发后只执行一次
/**
 * @param fn {Function} 实际要执行的函数
 * @param interval {Number} 延迟时间,默认 300 毫秒
 * 
 * @return {Function} 
 */

function debounce(fn, interval = 300) {
   let timer = null;
   return function() {
     clearTimeout(timer);
     timer = setTimeout(() => {
      fn.applay(this, arguments);
     }, interval);
   }
 }

@0uzu0
Copy link

0uzu0 commented May 24, 2019

防抖:在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。

function debounce(fn, wait) {
  var timer = null;
  return function () {
    var that = this
          var args = arguments
          if (timer) {
                clearTimeout(timer);
                timer = null;
          }
          timer = setTimeout(function () {
              fn.apply(that, args)
          }, wait)
  }
}
var fn = function () {
      console.log('boom')
}
setInterval(debounce(fn,500),1000) // 第一次在1500ms后触发,之后每1000ms触发一次
setInterval(debounce(fn,2000),1000) // 不会触发一次(我把函数防抖看出技能读条,如果读条没完成就用技能,便会失败而且重新读条)

节流:规定一个单位时间,在这个单位时间内,只能有一次触发事件的回调函数执行,如果在同一个单位时间内某事件被触发多次,只有一次能生效。

function throttle(fn, gapTime) {
  let _lastTime = null;
  return function () {
        let _nowTime = + new Date()
        if (_nowTime - _lastTime > gapTime || !_lastTime) {
            fn();
            _lastTime = _nowTime
        }
  }
}
let fn = ()=>{
    console.log('boom')
}
setInterval(throttle(fn,1000),10)

@zhangxianhui
Copy link

防抖函数作用

出现的原因

在某段连续时间内,多次触发请求 为造成资源浪费,为了解决客户端的性能问题 出现了防抖

什么是防抖

在某段连续时间内在事件触发后只执行一次

作用

解决高频繁问题,既能节省浏览器CPU资源,又能让页面浏览更加顺畅,不会因为js的执行而发生卡顿
出现场景:最常见的是搜索引擎 input 输入

实现

fangdou(fn, delay) {
let timeout;
let _arg;
return function(arg) {
_arg = arg;
if (timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(() => {
fn.call(this, _arg);
}, delay);
};
}

@toyxz
Copy link

toyxz commented May 24, 2019

防抖函数的作用是防止频繁触发某个事件

原理:利用定时器,当事件触发后一段该事件内再次触发,则重新开始计时,等到计时器结束之后,才做该事件的响应

应用场景:最常见的就是搜索框了,当我们一直键入的时候,键盘事件一直在触发,但是只有我们不键入一会,搜索框才会带着关键词去请求响应的数据回来。防抖减少网络请求等事件的次数。

写一个防抖:

function debounce(fn,interval) {
    let timer
    return function(...args) {
        if (timer) return false
        timer = setTimeout(() => {
            fn(...args)
            clearTimeout(timer)
        }, interval)
    }
}
const fn = debounce((...args) => console.log(args),1000)
fn(1,2)
fn(2,3)
fn(4,5)
fn(4,2)
// 只输出[1,2]

fn函数频繁调用,却只输出一次!

@luohong123
Copy link

luohong123 commented May 24, 2019

本题我重点从防抖的作用、概念应用场景、手写防抖函数方面回答,同时通过防抖和节流的区别,加深自己对防抖和节流知识点的理解。

一、概念

(一)防抖(debounce)的概念

防抖是触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间。每次触发事件时设置一个延迟调用方法,并且取消之前的延时调用方法。
image

(二)节流(throttle)的概念

节流是高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率。每次触发事件时,如果当前有等待执行的延时函数,则直接return。
image

二、作用

(一)防抖的作用

如果我们对函数的调用频率无限制,比如在实现模糊查询的时候,既会加重浏览器的负担,也会加重服务器的负担,防抖可以减少函数的调用频率,不影响功能的情况下,提升用户体验。

(二)节流的作用

节流就是在一定时间间隔内触发一次事件。减少触发事件的频率,提升性能。

三、防抖(debounce)和节流(throttle)的区别

函数节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数,列入水管的水滴在一定的间隔时间滴一滴水。而函数防抖只是在最后一次事件后才触发一次函数,如果中途再次触发,则再次重新开始计算时间,重新延迟。

四、应用场景

(一)防抖的应用场景

1、模糊查询

(二)节流的应用场景

1、滚动页面

五、手写代码

(一)手写防抖

通过定义一个是否执行函数的canRun标识,在没有超过约定时间内,如果再次触发函数,清除定时器,重新计算时间,直到到了约定时间后,才会调用函数。比如在实现模糊查询的时候,每个500ms向后台发起一个请求

  • 实现思路
    每次调用函数时,先清除定时器,重新计算时间,直到满足约定的时间后,再清除定时器
function debounce(fn, wait) {
    var timeout = null;
    return function() {
        if(timeout !== null) {
          clearTimeout(timeout);
        }
        timeout = setTimeout(fn, wait);
    }
}
// 处理函数
function handle() {
    console.log(Math.random()); 
}
// 滚动事件
window.addEventListener('scroll', debounce(handle, 1000));

##(二)手写节流

  • 实现思路
    调用函数时,通过上一次pre和现在now两个变量,记录调用时间的频率,prev-now 如果大于约定的时间,才调用函数。调用函数结束后,把pre设置为现在的时间。
 var throttle = function(func, delay) {
            var prev = Date.now();
            return function() {
                var context = this;
                var args = arguments;
                var now = Date.now();
                if (now - prev >= delay) {
                    func.apply(context, args);
                    prev = Date.now();
                }
            }
        }
        function handle() {
            console.log(Math.random());
        }
        window.addEventListener('scroll', throttle(handle, 1000));

六、参考文章

结语
我的回答如有不对的地方,麻烦务必指出来,我及时改正,以免误导别人,让我们共同进步吧!

@web-data-MrLi
Copy link

web-data-MrLi commented May 24, 2019

今天这个题看一些博客,还是有点不解,可能是在平时没有用到过的原因,这个防抖说的大概意思就是,函数执行完一次再去触发执行第二次,如果是这样的话,设置一个开关是否可行,还有设置一个倒计时,函数触发后倒计多少秒后在执行;
看了以上的各位的写的都差不多,还是对其一些传参不解,今天先记录一下吧;

var timer = null
function debounce(){
clearTimeout(timer)
timer = setTimeout(function(){
console.log(1)
}, 1000)
}
https://css-tricks.com/debouncing-throttling-explained-examples/值得一看
https://mp.weixin.qq.com/s/Vkshf-nEDwo2ODUJhxgzVA

@wubetter
Copy link

防抖

防抖(debounce) :当持续触发事件时,一定时间内没有再触发事件,事件处理函数才会执行* 一次 *,如果设定时间到来之前,又一次触发了事件,就重新开始延时。

function debounce(fn,delay){
   let timer = null;
   return function(){
       let ctx = this;
       let args = arguments;
       clearTimeout(timer);
       timer = setTimeout(()=>{
           fn.apply(ctx,args);
       },delay);
   }
}

防抖函数的应用

  • input输入框,在用户不断输入值时,用防抖来节约请求资源(百度输入框)
  • 邮箱,手机号等验证输入检测
  • window 触发resize的时候,不断调整窗口大小会不停的触发这个事件,可以用防抖来让其处理函数只触发一次

说了防抖,还有一个跟防抖比较类似的概念 :节流(throttle

节流

节流(throttle):当持续触发事件时,* 一定时间内只调用一次* 事件处理函数

function throttle(fn,delay){
    let timer = null;
    return function(){
        let ctx = this;
        let args = arguments;
        if(timer === null){
            timer = setTimeout(()=>{
                fn.apply(ctx,args);
                timer = null;
            },delay)
        }
    }
}

节流函数的应用

  • 滚动条滚动底部加载更多,监听滚动条位置
  • canvas动画函数 requestAnimationFrame

区别

虽然防抖和节流很像,他们都是在持续触发事件时,做一些相应的操作来实现节省资源,但是还是有一些不同

  • 防抖是规定时间内连续触发事件时,不会执行事件处理函数,当连续事件不触发时,之后的规定时间后触发一次
  • 节流是连续触发事件时,每隔一定的时间就会触发一次事件处理函数

@Diamondjcx
Copy link

在前端开发的过程中,我们经常会需要绑定一些持续触发的事件,如 resize、scroll、mousemove 等等,但有些时候我们并不希望在事件持续触发的过程中那么频繁地去执行函数。

防抖函数分为非立即执行版和立即执行版。

非立即执行版
触发事件后函数不会立即执行,而是在 n 秒后执行,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。(url)

function(url) debounce(func, wait) {
    let timeout;
    return function () {
        let context = this;
        let args = arguments;
        if (timeout) clearTimeout(timeout);
        timeout = setTimeout(() => {
            func.apply(context, args)
        }, wait);
    }
}

立即执行版
触发事件后函数会立即执行,然后 n 秒内不触发事件才能继续执行函数的效果。

function debounce(func,wait) {
    let timeout;
    return function () {
        let context = this;
        let args = arguments;
        if (timeout) clearTimeout(timeout);
        let callNow = !timeout;
        timeout = setTimeout(() => {
            timeout = null;
        }, wait)
        if (callNow) func.apply(context, args)
    }
}

@kaiking01
Copy link

防抖,又称函数节流,背后基本思想是指:某些代码不可以没有间断的情况连续重复执行。第一次调用函数,创建一个定时器,在指定的时间间隔之后运行代码。当第二次调用函数时,它会清除前一次的定时器并设置另一个。如果前一个定时器已经执行了,这个操作就没有任何意义。然而,如果前一个定时器尚未执行,其实就是将其替换为一个新的定时器。目的是只有在执行函数请求停止了一段时间之后才执行。

function throttle(fn, context){
 clearTimeout(fn.tId);
 fn.tId = setTimeout(function(){
    fn.apply(context, arguments)
 },200)
}

节流在resize事件中是最常用的,如下案例,设置一个div的高度适中和宽度保持一致
案例:

function resizeDiv(){
  var div = document.getElementById('#myDiv');
  div.style.height = div.offsetWidth + 'px';
}

window.onresize = function(){
  throttle(resizeDiv);
}

@qinmeishuying
Copy link

函数防抖是指对于在事件被触发n秒后再执行的回调,如果在这n秒内又重新被触发,则重新开始计时,是常见的优化,适用于:
1.表单组件输入内容验证
2.防止多次点击导致表单多次提交

等情况,防止函数过于频繁的不必要的调用。

function debounce(func, wait, immediate) {
let time
let debounced = function() {
let context = this
if(time) clearTimeout(time)

    if(immediate) {
        let callNow = !time
        if(callNow) func.apply(context, arguments)
        time = setTimeout(
            ()=>{time = null} //见注解
        , wait)
    } else {
        time = setTimeout(
            ()=>{func.apply(context, arguments)}
        , wait) 
    }
}

debounced.cancel = function() {
    clearTimeout(time)
    time = null
}

return debounced

}

@YvetteLau
Copy link
Owner Author

防抖函数的作用

防抖函数的作用就是控制函数在一定时间内的执行次数。防抖意味着N秒内函数只会被执行一次,如果N秒内再次被触发,则重新计算延迟时间。

举例说明: 小思最近在减肥,但是她非常贪吃。为此,与其男朋友约定好,如果10天不吃零食,就可以购买一个包(不要问为什么是包,因为包治百病)。但是如果中间吃了一次零食,那么就要重新计算时间,直到小思坚持10天没有吃零食,才能购买一个包。所以,管不住醉的小思,一次没有机会买包(悲伤的故事)...

不管吃没吃零食,每10天买一个包,是节流。而我们这是啥,这是防抖。如何控制女朋友的消费,各位攻城狮们,get到了吗?防抖可比节流有效多了!

防抖应用场景

  1. 搜索框输入查询,如果用户一直在输入中,没有必要不停地调用去请求服务端接口,等用户停止输入的时候,再调用,设置一个合适的时间间隔,有效减轻服务端压力。
  2. 表单验证
  3. 按钮提交事件。
  4. 浏览器窗口缩放,resize事件等。

防抖函数实现

function debounce(func, wait, immediate=true) {
    let timeout, context, args;
        // 延迟执行函数
        const later = () => setTimeout(() => {
            // 延迟函数执行完毕,清空定时器
            timeout = null
            // 延迟执行的情况下,函数会在延迟函数中执行
            // 使用到之前缓存的参数和上下文
            if (!immediate) {
                func.apply(context, args);
                context = args = null;
            }
        }, wait);
        let debounced = function (...params) {
            if (!timeout) {
                timeout = later();
                if (immediate) {
                    //立即执行
                    func.apply(this, params);
                } else {
                    //闭包
                    context = this;
                    args = params;
                }
            } else {
                clearTimeout(timeout);
                timeout = later();
            }
        }
    debounced.cancel = function () {
        clearTimeout(timeout);
        timeout = null;
    };
    return debounced;
};

偷个懒,睡睡睡觉去了~~~
周末整理的时候,我再好好完善下~~~
大家都辛苦啦~

@0xBrooke
Copy link

函数防抖(debounce):当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定的时间到来之前,又一次触发了事件,就重新开始延时。
作用:为了限制函数执行频率,优化函数触发频率过高导致的响应速度跟不上触发频率,出现页面延迟或者卡死的现象 ,优化性能,提高用户体验。

应用场景: 监听滚动事件,input 模糊搜索,图片的拖拽等

function debounce(func, wait) {
      var timeout;
      return function () {
          var context = this;
          var args = arguments;
          if (timeout) {
              clearTimeout(timeout)
          }
      
          timeout = setTimeout(function () {
               func.apply(context, args);
          }, wait)

      }
  }
  function onScroll_2() {
      console.log('监听窗口变化');
  }
  window.addEventListener('resize', debounce(onScroll_2, 1000));

@1353619565 写的非常好,学习了,多谢,重温一下

// 添加防抖函数
function debounce(fn, interval = 300) {
  let timeout = null;
  return function () {
    clearTimeout(timeout);
    timeout = setTimeout(() => {
      fn.apply(this, arguments);
    }, interval);
  };
}
$('input.user-name').on('input', debounce(function () {
  $.ajax({
    url: `https://just.com/check`,
    method: 'post',
    data: {
      username: $(this).val(),
    },
    success(data) {
      if (data.isRegistered) {
        $('.tips').text('该用户名已被注册!');
      } else {
        $('.tips').text('恭喜!该用户名还未被注册!');
      }
    },
    error(error) {
      console.log(error);
    },
  });
}));

@ZhangWeiC
Copy link

ZhangWeiC commented May 24, 2019

防抖的原理就是:你尽管触发事件,我反正在事件出发n秒之后才会执行,如果在一个事件触发之后的n内又触发了该事件,那就以新的事件的时间为准,n秒之后再执行。

//立即执行
function debounce(func, wait, immediate){
    var timer;

    return function(){
           const _this = this;
           const args = arguments;

           if(timer) clearInterval(timer);
           if(immediate){
                var callNow = !timer;
                timer = setTimeout(function(){
                    timer = null;
                }, wait);
               if(callNow) func.apply(_this, args);
           }else{
               timer = setTimeout(function(){
                   func.apply(_this, args);
               }, wait);
          }
    }
}

@tianyuandsb
Copy link

防抖函数理解:
定义:多次触发事件后,事件处理函数只执行一次,并且是在触发操作结束时执行。
原理:对处理函数进行延时操作,若设定的延时到来之前,再次触发事件,则清除上一次的延时操作定时器,重新定时。
function debounce(method,delay) {
let timer = null;
return function () {
let _this. = this,
let _args = arguments;
timer && clearTimeout(timer);
timer = setTimeout(function () {
method.apply(_this,_args);
},delay);
}
}

@zhmfe
Copy link

zhmfe commented May 25, 2019

函数防抖

  • 概念:在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。
  • 个人理解:如果有人进电梯(触发事件),那电梯将在10秒钟后出发(执行事件监听器),这时如果又有人进电梯了(在10秒内再次触发该事件),我们又得等10秒再出发(重新计时)。
//函数防抖,输入框应用
function debounce(fun, delay) {
    return function (args) {
        let that = this
        let _args = args
        clearTimeout(fun.id)
        fun.id = setTimeout(function () {
            fun.call(that, _args)
        }, delay)
    }
}
    
let inputb = document.getElementById('debounce')
let debounceAjax = debounce(ajax, 500)
inputb.addEventListener('keyup', function (e) {
        debounceAjax(e.target.value)
})

防抖应用场景

- search搜索联想,用户在不断输入值时,用防抖来节约请求资源。
- 表单验证 
- window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次

@zihuasunshine
Copy link

防抖和节流的概念

防抖(debounce)
函数在n秒内只执行一次,若这n秒内,函数高频触发,则会重新计算时间。

节流(throttle)
高频事件每隔n秒就会执行一次

//防抖代码实现
function debounce(func, delay) {
  return function(args) {
    let _this = this, _args = args; // 获取函数的作用域和变量
    clearTimeout(func.id);           //  每次触发 都清除当前timmer,重新设置时间
    func.id = setTimeout(function(){
     func.call(_this, args);
    }, delay);
  }
}
节流代码实现
function throttle(func, delay){
 let last, deferTime;
 return function(args){
   let this = _this, _args = args;
   let now = +new Date();
   if(last && now < last+delay) {
     clearTimeout(deferTime);
     deferTime = setTimeout(function() {
       func.call(_this, _args)
     }, delay);
   }else {
     last = now();
     func.call(_this, _args);
   }
  }
}

应用场景
防抖:

  1. 每次触发onresize,onscorll事件;
  2. 文本框输入验证(连续输入发送ajax请求,输入完成后验证一次就好);

节流:
1.DOM 元素的拖拽功能实现(mousemove)
2.射击游戏的 mousedown/keydown 事件(单位时间只能发射一颗子弹)
3.计算鼠标移动的距离(mousemove)
4.Canvas 模拟画板功能(mousemove)
5.搜索联想(keyup)
6.监听滚动事件判断是否到页面底部自动加载更多:给 scroll 加了 debounce 后,只有用户停止滚动后,才会判断是否到了页面底部;如果是 throttle 的话,只要页面滚动就会间隔一段时间判断一次

@ahaow
Copy link

ahaow commented May 26, 2019

理解函数防抖

函数防抖是指频繁触发的情况下,只有足够的空闲时间,才执行代码一次。

简单实现

funtion debounce(func,wait) {
	var timeout;
	return function() {
		var context = this;
		clearTimeout(timeout);
		timeout = setTimeout(function() {
			func.apply(context);	
		},wait)
	}
}

参考文章: JavaScript专题之跟着underscore学防抖

@noggcool
Copy link

防抖函数
在频繁触发某些事件,导致大量的计算或者非常消耗资源的操作的时候,防抖可以强制在一段连续的时间内只执行一次。
场景:input框搜索时,不会用户每进行操作就进行搜索,而是等用户输入完成后进行操作,所以可以使用防抖函数进行限制, 在一定时间内触发的事件只有到了指定的时间才发送一次请求。
const debounce = function (func,wait = 50) {
// 缓存一个定时器id
let timer = null;
// 这里返回的函数时每次用户实际调用的防抖函数
// 如果已经设定过定时器了就清空上一次的定时器
// 开始一个定时器,延迟执行用户传入的方法
return function(...args){
if(timer) clearTimeout(timer);
timer = setTimeout(()=>{
//将实际的this和参数传入用户实际调用的函数
func.apply(this,args);
},wait);
}
};
今天的题目不会
很开心,今天又有新的收获,谢谢大家的分享~

@gitluck1314
Copy link

问题1: 如果实现了dom拖拽功能,但是在绑定拖拽事件的时候发现每当元素稍微移动一点便触发了大量的回调函数,导致浏览器直接卡死,这个时候怎么办?

问题2:如果给一个按钮绑定了表单提交的post事件,但是用户有些时候在网络情况极差的情况下多次点击按钮造成表单重复提交,如何防止多次提交的发生?

1、定义

函数防抖(debounce)

当调用动作过n毫秒后,才会执行该动作,若在这n毫秒内又调用此动作则将重新计算执行时间

函数节流(throttle)

规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效。

2、作用

解决高频繁问题,既能节省浏览器CPU资源,又能让页面浏览更加顺畅,不会因为js的执行而发生卡顿

3、二者的区别

  • 函数防抖只是在最后一次事件后才触发一次函数;
  • 而函数节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数。

4、使用场景

防抖

  • search搜索联想,用户在不断输入值时(keyup,keydown),用防抖来节约请求资源。
  • 拖拽、鼠标移动(mousemove)事件
  • window触发resize的时候,不断的调整浏览器窗口大小,会不断的触发这个事件,用防抖来让其只触发一次

节流

  • 鼠标不断点击触发,mousedown(单位时间内只触发一次)
  • 监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断

5、实现

<div id='debounce' >
        <h3>这是防抖函数的例子</h3>
        <p>在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。</p>
        <div style="padding:10px">
              <strong>示例1:</strong>
              <input id="debounceInput" type="text">
        </div>
  
        <div style="padding:10px">
               <strong>示例2:</strong>
               <div id="debounceCount"></div>
        </div>
 </div>


 <div id='throttle'>
       <h3>这是节流函数的例子</h3>
       <p>规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效。</p>
       <button id='but' @click='throttleClick'>点击一下</button>
</div>

防抖

js代码:

  var fd = document.getElementById('debounceInput');
  var fdDivCount = document.getElementById('debounceCount');
  var count = 1;
  function outPut() {
    console.log('输出,', fd.value); 
  }

  function addWhenMove() {
    fdDivCount.innerHTML=count++;
  }

 // 防抖函数
  function _debounce(fun,delayTime) {
     var delayTime = delayTime || 500;
     var timer;
     return function () {
         var that =this;
         var args = arguments;
         if(timer){
              clearTimeout(timer);
         }
         timer = setTimeout(() => {
              fun.apply(that,args)
         }, delayTime);
      }
  }
 fd.addEventListener('keyup', _debounce(outPut, 1000))
 fdDivCount.onmousemove = _debounce(addWhenMove, 1000,true)

运行效果:

示例1:
image

示例2:
image

节流

js代码:

   new Vue({
       el:'#throttle',
       data:{},
       methods:{
         throttleClick:function (){
            let that = this
            let now = +new Date();
            if (lastTime && lastTime - now < 1000) {
               clearTimeout(timer);
            }
            timer = setTimeout(() => {
               console.log('点击一下');
               lastTime = +new Date()
            }, 1000);
          }
        }
     })

运行效果:
image


如果错误请指出,谢谢!>_<

参考链接:https://juejin.im/post/5b8de829f265da43623c4261#heading-2

@KRISACHAN
Copy link

KRISACHAN commented May 26, 2019

防抖是什么?

防抖是什么?防抖就是防止抖动,例如小朋友喜欢多动,停不下来,然后做家长的打一顿,让小朋友安静下来,这种行为就叫做防抖。

(~o ̄3 ̄)~

biu

抖个机灵,哈哈哈~

抖动是一个很常见的控制函数在一定时间内执行多少次的技巧,其实就是确定了函数执行的最小间隔,如果还在这个间隔内触发函数,则重新计算。

举个栗子~

你家有七个儿子,大儿子叫大娃,二儿子叫二娃,三儿子叫三娃,四儿子叫四娃,五儿子叫五娃,六儿子叫六娃,七儿子叫七娃。由于七个孩子还小,他们的衣服你只能用手洗,一洗洗七套,一次要一个小时。如果洗到一半,你的七个孩子给你过来捣乱把衣服弄脏,那么你又得花一个小时去洗,不捣乱,那么你一个小时之后你的孩子衣服就又脏了,又可以再花一个小时来洗衣服了。

具体实现

鱼头注:以下代码来自优秀的JS库 lodash

// 判断是不是个对象
function isObject(value) {
  const type = typeof value
  return value != null && (type == 'object' || type == 'function')
}

/*
 * 创建一个 debounced 函数,延迟调用 func 直到 wait 之后
 * cancel 方法用于取消 debounced
 * flush 方法用于立即调用
 */

function debounce(func, wait, options) {
  let lastArgs,
    lastThis,
    maxWait,
    result,
    timerId,
    lastCallTime

  let lastInvokeTime = 0
  let leading = false
  let maxing = false
  let trailing = true

  // 绕过 requestAnimationFrame ,显式地设置 wait = 0
  const useRAF = (!wait && wait !== 0 && typeof root.requestAnimationFrame === 'function')

  if (typeof func !== 'function') {
    throw new TypeError('Expected a function')
  }
  wait = +wait || 0
  if (isObject(options)) {
    leading = !!options.leading
    maxing = 'maxWait' in options
    maxWait = maxing ? Math.max(+options.maxWait || 0, wait) : maxWait
    trailing = 'trailing' in options ? !!options.trailing : trailing
  }

  function invokeFunc(time) {
    const args = lastArgs
    const thisArg = lastThis

    lastArgs = lastThis = undefined
    lastInvokeTime = time
    result = func.apply(thisArg, args)
    return result
  }

  function startTimer(pendingFunc, wait) {
    if (useRAF) {
      root.cancelAnimationFrame(timerId);
      return root.requestAnimationFrame(pendingFunc)
    }
    return setTimeout(pendingFunc, wait)
  }

  function cancelTimer(id) {
    if (useRAF) {
      return root.cancelAnimationFrame(id)
    }
    clearTimeout(id)
  }

  function leadingEdge(time) {
    // 重置任何 最大等待时间的计时器
    lastInvokeTime = time
    // 启动计时器
    timerId = startTimer(timerExpired, wait)
    // 返回调用结果
    return leading ? invokeFunc(time) : result
  }

  function remainingWait(time) {
    const timeSinceLastCall = time - lastCallTime
    const timeSinceLastInvoke = time - lastInvokeTime
    const timeWaiting = wait - timeSinceLastCall

    return maxing
      ? Math.min(timeWaiting, maxWait - timeSinceLastInvoke)
      : timeWaiting
  }

  function shouldInvoke(time) {
    const timeSinceLastCall = time - lastCallTime
    const timeSinceLastInvoke = time - lastInvokeTime

    // 判断是否应该调用函数
    return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||
      (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait))
  }

  function timerExpired() {
    const time = Date.now()
    if (shouldInvoke(time)) {
      return trailingEdge(time)
    }
    // 重置定时器
    timerId = startTimer(timerExpired, remainingWait(time))
  }

  function trailingEdge(time) {
    timerId = undefined

    // 如果我有最后一个参数,就意味着函数需要调用
    // 至少执行一次防抖
    if (trailing && lastArgs) {
      return invokeFunc(time)
    }
    lastArgs = lastThis = undefined
    return result
  }

  function cancel() {
    if (timerId !== undefined) {
      cancelTimer(timerId)
    }
    lastInvokeTime = 0
    lastArgs = lastCallTime = lastThis = timerId = undefined
  }

  function flush() {
    return timerId === undefined ? result : trailingEdge(Date.now())
  }

  function pending() {
    return timerId !== undefined
  }

  function debounced(...args) {
    const time = Date.now()
    const isInvoking = shouldInvoke(time)

    lastArgs = args
    lastThis = this
    lastCallTime = time

    if (isInvoking) {
      if (timerId === undefined) {
        return leadingEdge(lastCallTime)
      }
      if (maxing) {
        // 处理循环调用
        timerId = startTimer(timerExpired, wait)
        return invokeFunc(lastCallTime)
      }
    }
    if (timerId === undefined) {
      timerId = startTimer(timerExpired, wait)
    }
    return result
  }
  debounced.cancel = cancel
  debounced.flush = flush
  debounced.pending = pending
  return debounced
}

使用方法如下:

var 打印一些东西啦 = function (event) {
	console.log(event);
};

document.querySelector('html').addEventListener('click', debounce(打印一些东西啦, 1000));

适用场景

以下就举几个我们日常开发中可能会用上 debounce 的栗子:

  • 输入框搜索,当用户停止搜索一段时间之后再执行请求操作,防止多次触发而给服务端带来压力
  • 防止重复触发 resize 或者 scroll 事件
  • 还有吧,但是懒得动脑了~

@954545647
Copy link

防抖主要用在滚动条事件中,比如监听滚动条事件,为避免一秒内多次触发,利用防抖就可以做到在固定时间内不会多次执行

防抖的核心方法就是利用定时器

function debounce(fn,delay){
 let timer = null;
 return function(){
  if(timer){
   clearTimeout(timer)
}
timer= setTimeout(fn,delay)
}
}

@DazhiFe
Copy link

DazhiFe commented May 26, 2019

先假设一个场景:通常用户注册的时候,需要填写用户名,在用户输入用户名的过程中,我们可以主动发请求到后端去验证当前的用户名是否已经被注册。

<input type="text" onKeyUp="keyup()">
var keyup = function () {
    // 将value发送给后端验证
}

如果用户想输入的用户名是helloworld,那么实际上在连续输完整个字符串后已经发了10次的验证请求了,很明显是存在问题的,因为用户只想知道helloworld整个字符串是否被注册,而不是每输入一个字符串就去给我验证。

所以,本质上,我们要解决的问题就是,预测用户是否已经输入完成。我们可以认为,用户每停顿800毫秒以上的实际,默认已经完成,然后再去验证。

var timer;
var keyup = function () {
    clearTimeout(timer);
    timer = setTimeout(function () {
        // 将value发送给后端验证
    }, 800);
}

只要我们认为用户还在规定的时间间隔内触发事件,那么就会一直等待下去,这个就叫做防抖

简单来说,防抖的作用就是为了防止高频率事件触发导致的性能问题。

@jodiezhang
Copy link

防抖的原理就是设定定时器,例如scroll事件连续触发,并不会每一次触发都会调用处理方法,而是等某一次触发停止了一段时间(定时器设定的时间)后,进行处理方法的调用。如果在设定的时间还没有到,就再次触发,那么清空之前的定时器,重新计时,直到scroll事件触发停止了一段时间(定时器设定的时间),执行处理方法。
每滚动一次滚动条,就会触发多次scroll事件,如果每次触发都要执行函数,开销很大。

基础比较差,看了下lodash库的debounce实现,还没有看懂,这个效率真是让人着急。
留个文章,还是要再仔细看一下。
https://segmentfault.com/a/1190000018205319?utm_source=tag-newest

@ivan0525
Copy link

  • 防抖函数是为了控制函数在一定时间内执行的次数。如果在规定时间内触发函数,就会重新计算时间。
function debounce (fn, delay, immediate) {
  let timeout = null
  return function () {
    clearTimeout(timeout)
    let context = this
    let args = arguments
    if (!timeout && immediate) {
      fn.apply(context, args)
    }
    timeout = setTimeout(() => {
      if (!immediate) {
        fn.apply(context, args)
      } else {
        immediate = null
      }
    }, delay)
  }
}

@noggcool
Copy link

noggcool commented Jun 3, 2019

重新回答一次
防抖函数的作用是什么?
防抖函数是控制函数执行的次数,在一定时间内,如果事件没有触发则执行。如果有事件触发,则推迟函数执行(重新计算延迟时间)。防抖函数的存在可以避免频繁的向服务器发送请求,影响性能。
应用场景:
input框搜索、表单验证、resize切换屏幕等
function debounce (fn,wait) { var timer = null; return function(){ if(timer != null){ clearTimeOut(timer) } timer = setTimeout(fn,wait) } } function handle () { 执行函数 } window.addEventListener('scroll',debounce(handle,2000))

@dunkezhang
Copy link

什么是防抖

当持续触发事件时,一定范围时间内没有再触发事件,事件处理函数才会执行一次,如果设定的时间到来之前,又一次触发事件,就重新开始延时

举例说明:当你乘电梯时,按下关电梯按钮,现在开始计时,如果5s内没有人点击开电梯按钮,你就会正常的乘着电梯上楼,如果5s内有人点击开电梯按钮,那么关门事件会重新开始延时5s再触发

什么是节流

当持续触发事件时,保证一定时间段内只调用一次事件处理函数。

举例说明:身为一个妹子,特别喜欢买化妆品。为了控制自己,节约钱,规定自己一个月买一次化妆品。

作用

处理高频事件,避免函数频繁调用,优化性能,减少浏览器或者服务器的压力。

防抖函数的应用场景

规定时间多次触发,以最后一次结果为准

  1. 输入框格式验证
  2. 输入框模糊搜索。输入框输入数据后向服务端请求数据拉一个列表。

节流函数的应用场景

规定时间只触发一次,不以结果为准

  1. 屏幕尺寸变化时,执行相应逻辑
  2. 监听鼠标滚动事件,执行相应逻辑
  3. 监听重复点击事件,执行相应逻辑

防抖函数的实现

  function denounce(func,delay) {
      let timerId = null
      return function(){
        window.clearTimeout(timerId)
        let context = this
        let args = arguments
        timerId = setTimeout(()=>{
          func.call(context,args)
        },time)
      }
    }

节流函数的实现

function throttle(func, time) {
      let preTime = 0
      return function() {
        let currentTime = Date.now()
        let context = this
        let args = arguments
        if(currentTime-preTime>time){
          func.call(context,args)
          preTime = Date.now()
        }
      }
    }

参考资料

js防抖和节流

@EcSunshine
Copy link

EcSunshine commented Jun 9, 2019

函数节流(throttle):当持续触发事件时,保证一定时间段内只调用一次事件处理函数
函数防抖(debounce):当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定的时间到来之前,又一次触发了事件,就重新开始延时
1搜索框输入查询,如果用户一直在输入中,没有必要不停地调用去请求服务端接口,等用户停止输入的时候,再调用,设置一个合适的时间间隔,有效减轻服务端压力。
2表单验证
3按钮提交事件。
4浏览器窗口缩放,resize事件等。

function debounce(func, wait, immediate=true) {
let timeout, context, args;
// 延迟执行函数
const later = () => setTimeout(() => {
// 延迟函数执行完毕,清空定时器
timeout = null
// 延迟执行的情况下,函数会在延迟函数中执行
// 使用到之前缓存的参数和上下文
if (!immediate) {
func.apply(context, args);
context = args = null;
}
}, wait);
let debounced = function (...params) {
if (!timeout) {
timeout = later();
if (immediate) {
//立即执行
func.apply(this, params);
} else {
//闭包
context = this;
args = params;
}
} else {
clearTimeout(timeout);
timeout = later();
}
}
debounced.cancel = function () {
clearTimeout(timeout);
timeout = null;
};
return debounced;
};

@riluocanyang
Copy link

防抖函数的作用

函数防抖是指对于高频事件,在规定时间内,如果事件没有被再次触发则执行回调函数,如果事件被再次触发,则重新开始计时。

防抖函数的应用场景

1、按钮提交
2、输入框验证

防抖函数的实现

function debounce(fn, delay) {
  var timer = null;
  return function () {
    var context = this, args = arguments;
    clearTimeout(timer);
    timer = setTimeout(function () {
      fn.apply(context, args);
    }, delay);
  };
}

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

No branches or pull requests