JS防抖和节流实例解析


Posted in Javascript onSeptember 24, 2019

日常开发过程中,滚动事件做复杂计算频繁调用回调函数很可能会造成页面的卡顿,这时候我们更希望把多次计算合并成一次,只操作一个精确点,JS把这种方式称为debounce(防抖)和throttle(节流)

函数防抖

当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定时间到来之前,又触发了事件,就重新开始延时。也就是说当一个用户一直触发这个函数,且每次触发函数的间隔小于既定时间,那么防抖的情况下只会执行一次。

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

JS防抖和节流实例解析

如上所见,当持续触发scroll函数,handle函数只会在1秒时间内执行一次,在滚动过程中并没有持续执行,有效减少了性能的损耗

函数节流

当持续触发事件时,保证在一定时间内只调用一次事件处理函数,意思就是说,假设一个用户一直触发这个函数,且每次触发小于既定值,函数节流会每隔这个时间调用一次

用一句话总结防抖和节流的区别:防抖是将多次执行变为最后一次执行,节流是将多次执行变为每隔一段时间执行
实现函数节流我们主要有两种方法:时间戳和定时器

例如

var throttle = function(func, delay) {
  var prev = Date.now();
  return function() {
    var context = this;  //this指向window
    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));

这个节流函数利用时间戳让第一次滚动事件执行一次回调函数,此后每隔1000ms执行一次,在小于1000ms这段时间内的滚动是不执行的
再举一个定时器的例子:

var throttle = function(func, delay) {
  var timer = null;
  return function() {
    var context = this;
    var args = arguments;
    if (!timer) {
      timer = setTimeout(function() {
        func.apply(context, args);
        timer = null;
      }, delay);
    }
  }
}
function handle() {
  console.log(Math.random());
}
window.addEventListener('scroll', throttle(handle, 1000));

当触发事件的时候,我们设置了一个定时器,在没到1000ms之前这个定时器为null,而到了规定时间执行这个函数并再次把定时器清除。也就是说当第一次触发事件,到达规定时间再执行这个函数,执行之后马上清除定时器,开始新的循环,那么我们看到的效果就是,滚动之后没有马上打印,而是等待1000ms打印,有一个延迟的效果,并且这段时间滚动事件不会执行函数。
单用时间戳或者定时器都有缺陷,我们更希望第一次触发马上执行函数,最后一次触发也可以执行一次事件处理函数

var throttle = function(func, delay) {
   var timer = null;
   var startTime = Date.now(); //设置开始时间
   return function() {
       var curTime = Date.now();
       var remaining = delay - (curTime - startTime); //剩余时间
       var context = this;
       var args = arguments;
       clearTimeout(timer);
       if (remaining <= 0) {   // 第一次触发立即执行
          func.apply(context, args);
          startTime = Date.now();
       } else {
          timer = setTimeout(func, remaining);  //取消当前计数器并计算新的remaining
       }
   }
}
function handle() {
   console.log(Math.random());
}
 window.addEventListener('scroll', throttle(handle, 1000));

JS防抖和节流实例解析

在节流函数内部使用开始时间startTime、当前时间curTime和剩余时间remaining,当剩余时间小于等于0意味着执行处理函数,这样保证第一次就能立即执行函数并且每隔delay时间执行一次;如果还没到时间,就会在remaining之后触发,保证最后一次触发事件也能执行函数,如果在remaining时间内又触发了滚动事件,那么会取消当前的计数器并计算出新的remaing时间。通过时间戳和定时器的方法,我们实现了第一次立即执行,最后一次也执行,规定时间间隔执行的效果,可以灵活运用在开发中

PS:防抖和节流能有效减少浏览器引擎的损耗,防止出现页面堵塞卡顿现象,应该熟练掌握。最后再次感谢原作者的总结,热心分享技术让我们的生活变得更好

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
onpropertypchange
Jul 01 Javascript
JS 显示当前日期与时间的代码
Mar 24 Javascript
jquery实现的带缩略图的焦点图片切换(自动播放/响应鼠标动作)
Jan 23 Javascript
JavaScript获取onclick、onchange等事件值的代码
Jul 22 Javascript
javascript获取四位数字或者字母的随机数
Jan 09 Javascript
JavaScript中setMonth()方法的使用详解
Jun 11 Javascript
JS提示:Uncaught SyntaxError:Unexpected token ) 错误的解决方法
Aug 19 Javascript
Javascript ES6中对象类型Sets的介绍与使用详解
Jul 17 Javascript
vue2.x 父组件监听子组件事件并传回信息的方法
Jul 17 Javascript
深入理解requireJS-实现一个简单的模块加载器
Jan 15 Javascript
解决使用Vue.js显示数据的时,页面闪现原始代码的问题
Feb 11 Javascript
vue实现树形结构样式和功能的实例代码
Oct 15 Javascript
vue.js实现图书管理功能
Sep 24 #Javascript
layui table单元格事件修改值的方法
Sep 24 #Javascript
Javascript Dom元素获取和添加详解
Sep 24 #Javascript
微信小程序全局变量的设置、使用、修改过程解析
Sep 24 #Javascript
layui监听select变化,以及设置radio选中的方法
Sep 24 #Javascript
layui 监听select选择 获取当前select的ID名称方法
Sep 24 #Javascript
layui监听下拉选框选中值变化的方法(包含监听普通下拉选框)
Sep 24 #Javascript
You might like
PHP 实例化类的一点摘记
2008/03/23 PHP
浅析PHP中的字符串编码转换(自动识别原编码)
2013/07/02 PHP
浅析PHP中strlen和mb_strlen的区别
2014/08/31 PHP
PHP微信开发之文本自动回复
2016/06/23 PHP
PHP+mysql防止SQL注入的方法小结
2019/04/27 PHP
JS实现图片横向滚动效果示例代码
2013/09/04 Javascript
一个CSS+jQuery实现的放大缩小动画效果
2014/02/19 Javascript
Iframe实现跨浏览器自适应高度解决方法
2014/09/02 Javascript
javascript模拟post提交隐藏地址栏的参数
2014/09/03 Javascript
jQuery中removeClass()方法用法实例
2015/01/05 Javascript
jQuery中first()方法用法实例
2015/01/06 Javascript
js点击返回跳转到指定页面实现过程
2020/08/20 Javascript
nodejs搭建本地http服务器教程
2017/03/13 NodeJs
微信小程序 蓝牙的实现实例代码
2017/06/27 Javascript
pm2 部署 node的三种方法示例
2017/10/20 Javascript
11行JS代码制作二维码生成功能
2018/03/09 Javascript
jQuery实现侧边栏隐藏与显示的方法详解
2018/12/22 jQuery
vue 限制input只能输入正数的操作
2020/08/05 Javascript
Python针对给定列表中元素进行翻转操作的方法分析
2018/04/27 Python
如何在Python3中使用telnetlib模块连接网络设备
2020/09/21 Python
Html5新特性用canvas标签画多条直线附效果截图
2014/06/30 HTML / CSS
查询优化的一般准则有哪些
2015/03/08 面试题
高中毕业生个人自我鉴定
2013/11/24 职场文书
岳父生日宴会答谢词
2014/01/13 职场文书
开工庆典邀请函范文
2014/01/16 职场文书
自行车租赁公司创业计划书
2014/01/28 职场文书
2014元旦晚会策划方案
2014/02/19 职场文书
优秀团员自我评价范文
2014/04/23 职场文书
投标诚信承诺书
2014/05/26 职场文书
小学母亲节活动总结
2015/02/10 职场文书
教师读书活动心得体会
2016/01/14 职场文书
七年级上册生物的课件
2019/08/07 职场文书
漫改真人电影「萌系男友是燃燃的橘色」公开先导视觉图
2022/03/21 日漫
MySQL Server层四个日志的实现
2022/03/31 MySQL
【海涛dota】偶遇拉娜娅 质量局德鲁伊第一视角解说
2022/04/01 DOTA
CSS的calc函数用法小结
2022/06/25 HTML / CSS