js防抖和节流的深入讲解

所属分类: 网络编程 / JavaScript 阅读数: 902
收藏 0 赞 0 分享

前言:

我们在做页面事件绑定的时候,经常要进行节流处理,比如鼠标异步点击,去执行一个异步请求时,需要让它在上一次没执行时不能再点击,又或者绑定滚动事件,这种持续触发进行dom判断的时候,就要按一定频率的执行。

本文主要给大家介绍了关于js防抖和节流的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧

0. 引入

首先举一个例子:

模拟在输入框输入后做ajax查询请求,没有加入防抖和节流的效果,这里附上完整可执行代码:

<!DOCTYPE html>
<html lang="en">

<head>
 <meta charset="UTF-8">
 <title>没有防抖</title>
 <style type="text/css"></style>
 <script type="text/javascript">
 window.onload = function () {
 //模拟ajax请求
 function ajax(content) {
 console.log('ajax request ' + content)
 }
 let inputNormal = document.getElementById('normal');

 inputNormal.addEventListener('keyup', function (e) {
 ajax(e.target.value)
 })
 }
 </script>
</head>

<body>
 <div>
 1.没有防抖的输入:
 <input type="text" name="normal" id="normal">
 </div>
</body>

</html>

效果:在输入框里输入一个,就会触发一次“ajax请求”(此处是console)。


没有防抖和节流

缺点:浪费请求资源,可以加入防抖和节流来优化一下。

本文会分别介绍什么是防抖和节流,它们的应用场景,和实现方式。防抖和节流都是为了解决短时间内大量触发某函数而导致的性能问题,比如触发频率过高导致的响应速度跟不上触发频率,出现延迟,假死或卡顿的现象。但二者应对的业务需求不一样,所以实现的原理也不一样,下面具体来看看吧。

1. 防抖(debounce)

1.1 什么是防抖

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

1.2 应用场景

(1) 用户在输入框中连续输入一串字符后,只会在输入完后去执行最后一次的查询ajax请求,这样可以有效减少请求次数,节约请求资源;

(2) window的resize、scroll事件,不断地调整浏览器的窗口大小、或者滚动时会触发对应事件,防抖让其只触发一次;

1.3 实现

还是上述列子,这里加入防抖来优化一下,完整代码如下:

<!DOCTYPE html>
<html lang="en">

<head>
 <meta charset="UTF-8">
 <title>加入防抖</title>
 <style type="text/css"></style>
 <script type="text/javascript">
 window.onload = function () {
  //模拟ajax请求
  function ajax(content) {
  console.log('ajax request ' + content)
  }
  function debounce(fun, delay) {
  return function (args) {
   //获取函数的作用域和变量
   let that = this
   let _args = args
   //每次事件被触发,都会清除当前的timeer,然后重写设置超时调用
   clearTimeout(fun.id)
   fun.id = setTimeout(function () {
   fun.call(that, _args)
   }, delay)
  }
  }
  let inputDebounce = document.getElementById('debounce')
  let debounceAjax = debounce(ajax, 500)
  inputDebounce.addEventListener('keyup', function (e) {
  debounceAjax(e.target.value)
  })
 }
 </script>
</head>

<body>
 <div>
 2.加入防抖后的输入:
 <input type="text" name="debounce" id="debounce">
 </div>
</body>

</html>

代码说明:

1.每一次事件被触发,都会清除当前的 timer 然后重新设置超时调用,即重新计时。 这就会导致每一次高频事件都会取消前一次的超时调用,导致事件处理程序不能被触发;

2.只有当高频事件停止,最后一次事件触发的超时调用才能在delay时间后执行;

效果:

加入防抖后,当持续在输入框里输入时,并不会发送请求,只有当在指定时间间隔内没有再输入时,才会发送请求。如果先停止输入,但是在指定间隔内又输入,会重新触发计时。

加入防抖

2.节流(throttle)

2.1 什么是节流

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

2.2 应用场景

(1)鼠标连续不断地触发某事件(如点击),只在单位时间内只触发一次;

(2)在页面的无限加载场景下,需要用户在滚动页面时,每隔一段时间发一次 ajax 请求,而不是在用户停下滚动页面操作时才去请求数据;

(3)监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断;

2.3 实现

还是上述列子,这里加入节流来优化一下,完整代码如下:

<!DOCTYPE html>
<html lang="en">

<head>
 <meta charset="UTF-8">
 <title>加入节流</title>
 <style type="text/css"></style>
 <script type="text/javascript">
 window.onload = function () {
  //模拟ajax请求
  function ajax(content) {
  console.log('ajax request ' + content)
  }

  function throttle(fun, delay) {
  let last, deferTimer
  return function (args) {
   let that = this;
   let _args = arguments;

   let now = +new Date();
   if (last && now < last + delay) {
   clearTimeout(deferTimer);
   deferTimer = setTimeout(function () {
    last = now;
    fun.apply(that, _args);
   }, delay)
   } else {
   last = now;
   fun.apply(that, _args);
   }
  }
  }
  let throttleAjax = throttle(ajax, 1000)
  let inputThrottle = document.getElementById('throttle')
  inputThrottle.addEventListener('keyup', function (e) {
  throttleAjax(e.target.value)
  })
 }
 </script>
</head>

<body>
 <div>
 3.加入节流后的输入:
 <input type="text" name="throttle" id="throttle">
 </div>
</body>

</html>

效果:实验可发现在持续输入时,会安装代码中的设定,每1秒执行一次ajax请求


加入节流

3. 小结

总结下防抖和节流的区别:

-- 效果:

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

-- 原理:

防抖是维护一个计时器,规定在delay时间后触发函数,但是在delay时间内再次触发的话,都会清除当前的 timer 然后重新设置超时调用,即重新计时。这样一来,只有最后一次操作能被触发。

节流是通过判断是否到达一定时间来触发函数,若没到规定时间则使用计时器延后,而下一次事件则会重新设定计时器。

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。

更多精彩内容其他人还在看

AngularJs IE Compatibility 兼容老版本IE

本文主要介绍AngularJs IE Compatibility 兼容老版本IE的问题及解决办法,有兴趣的小伙伴可以参考下
收藏 0 赞 0 分享

AngularJs Modules详解及示例代码

本文主要介绍AngularJs Modules的相关知识,这里整理了详细的资料及简单示例代码,有兴趣的朋友可以参考下
收藏 0 赞 0 分享

AngularJs Scope详解及示例代码

本文主要介绍AngularJs Scope的知识,这里整理了详细资料及示例代码,有兴趣的小伙伴可以参考下
收藏 0 赞 0 分享

node.js中module.exports与exports用法上的区别

Node.js 引入了模块(Module)概念,一个模块可以通过module.exports 或 exports 将函数、变量等导出,以使其它 JavaScript 脚本通过require() 函数引入并使用。那么node.js中module.exports与exports有什么
收藏 0 赞 0 分享

基于JS实现发送短信验证码后的倒计时功能(无视页面刷新,页面关闭不进行倒计时功能)

这篇文章主要介绍了基于JS实现发送短信验证码后的倒计时功能(无视页面刷新,页面关闭不进行倒计时功能)的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下
收藏 0 赞 0 分享

基于jQuery实现发送短信验证码后的倒计时功能(无视页面关闭)

最近做了一个项目,其中有需求要求实现发送短信验证码后倒计时功能,其中有个难点:要求关闭页面也进行倒计时。好吧,下面小编把jquery 发送验证码倒计时的实现代码分享给大家,大家可以参考下
收藏 0 赞 0 分享

js绘制购物车抛物线动画

这篇文章主要为大家详细介绍了js绘制购物车抛物线动画,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

vue.js入门教程之绑定class和style样式

小编之前介绍了通过vue.js计算属性,不知道大家都学会了吗。那这篇文章中我们将一起学习vue.js实现绑定class和style样式,有需要的朋友们可以参考借鉴。
收藏 0 赞 0 分享

纯JS实现可拖拽表单的简单实例

下面小编就为大家带来一篇纯JS实现可拖拽表单的简单实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

js实现StringBuffer的简单实例

下面小编就为大家带来一篇js实现StringBuffer的简单实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享
查看更多