防抖节流(回顾)

news2024/9/27 15:34:06

  • 防抖
    • 定义
    • 应用场景:
    • 实现思路:
    • _.debounce 源码
  • 节流
    • 定义
    • 应用场景:
    • 实现思路:
    • _.throttle
  • 防抖和节流的区别
    • scroll 事件下的区别
    • mousemove 事件下的区别

防抖

定义

强制函数在固定时间只执行一次,多余执行无效

应用场景:

  1. 按钮的防二次点击操作 视频参考

实现思路:

  1. 开启一个延时器,只要延时器还在,不管怎么点击都不执行回调函数
  2. 一旦延时器结束并设置为 null,就可以再次点击
  3. 需要考虑的点:this指向, 事件源对象的获取(参数)
    在这里插入图片描述
//ES6
function debounce(fn, delay, timer = null) {
  return function (...args) {
    clearTimeout(timer);
    timer = setTimeout(fn.bind(this, ...args), delay);
  };
}
//ES3 推荐
function debounce(fn, delay, timer = null) {
  return function () {
    let self = this
    let arg = arguments
    clearTimeout(timer);
    timer = setTimeout(function () {
      fn.apply(self, arg);
    }, delay);
  };
}

_.debounce 源码

// 使用 underscore 的源码来解释防抖动
/**
 * underscore 防抖函数,返回函数连续调用时,空闲时间必须大于或等于 wait,func 才会执行
 *
 * @param  {function} func        回调函数
 * @param  {number}   wait        表示时间窗口的间隔
 * @param  {boolean}  immediate   设置为ture时,是否立即调用函数
 * @return {function}             返回客户调用函数
 */
_.debounce = function(func, wait, immediate) {
    var timeout, args, context, timestamp, result;

    var later = function() {
      // 现在和上一次时间戳比较
      var last = _.now() - timestamp;
      // 如果当前间隔时间少于设定时间且大于0就重新设置定时器
      if (last < wait && last >= 0) {
        timeout = setTimeout(later, wait - last);
      } else {
        // 否则的话就是时间到了执行回调函数
        timeout = null;
        if (!immediate) {
          result = func.apply(context, args);
          if (!timeout) context = args = null;
        }
      }
    };

    return function() {
      context = this;
      args = arguments;
      // 获得时间戳
      timestamp = _.now();
      // 如果定时器不存在且立即执行函数
      var callNow = immediate && !timeout;
      // 如果定时器不存在就创建一个
      if (!timeout) timeout = setTimeout(later, wait);
      if (callNow) {
        // 如果需要立即执行函数的话 通过 apply 执行
        result = func.apply(context, args);
        context = args = null;
      }

      return result;
    };
  };

节流

定义

强制函数以规定频率执行

应用场景:

  1. scroll事件,每隔一秒计算一次位置信息
  2. 浏览器播放事件,每一秒计算一次进度信息

实现思路:

  1. 设置一个lock,只要lock还在,就不执行延时器里的回调函数
  2. 每隔一段时间,就把lock打开,执行延时器中的回调函数
  3. 需要考虑的点:this指向, 事件源对象的获取(参数)
//ES6
function throttle(fn, delay) {
  let lock = false;
  return function (...args) {
    if (lock) return;
    fn.apply(this, args);
    lock = true;
    setTimeout(() => (lock = false), delay);
  };
}
//ES3
function throttle(fn, delay) {
  var lock = false;
  return function () {
    if (lock) return;
    fn.apply(this, arguments);
    lock = false;
    setTimeout(() => (lock = true), delay);
  };
}

_.throttle

/**
 * underscore 节流函数,返回函数连续调用时,func 执行频率限定为 次 / wait
 *
 * @param  {function}   func      回调函数
 * @param  {number}     wait      表示时间窗口的间隔
 * @param  {object}     options   如果想忽略开始函数的的调用,传入{leading: false}。
 *                                如果想忽略结尾函数的调用,传入{trailing: false}
 *                                两者不能共存,否则函数不能执行
 * @return {function}             返回客户调用函数   
 */
_.throttle = function(func, wait, options) {
    var context, args, result;
    var timeout = null;
    // 之前的时间戳
    var previous = 0;
    // 如果 options 没传则设为空对象
    if (!options) options = {};
    // 定时器回调函数
    var later = function() {
      // 如果设置了 leading,就将 previous 设为 0
      // 用于下面函数的第一个 if 判断
      previous = options.leading === false ? 0 : _.now();
      // 置空一是为了防止内存泄漏,二是为了下面的定时器判断
      timeout = null;
      result = func.apply(context, args);
      if (!timeout) context = args = null;
    };
    return function() {
      // 获得当前时间戳
      var now = _.now();
      // 首次进入前者肯定为 true
	  // 如果需要第一次不执行函数
	  // 就将上次时间戳设为当前的
      // 这样在接下来计算 remaining 的值时会大于0
      if (!previous && options.leading === false) previous = now;
      // 计算剩余时间
      var remaining = wait - (now - previous);
      context = this;
      args = arguments;
      // 如果当前调用已经大于上次调用时间 + wait
      // 或者用户手动调了时间
 	  // 如果设置了 trailing,只会进入这个条件
	  // 如果没有设置 leading,那么第一次会进入这个条件
	  // 还有一点,你可能会觉得开启了定时器那么应该不会进入这个 if 条件了
	  // 其实还是会进入的,因为定时器的延时
	  // 并不是准确的时间,很可能你设置了2秒
	  // 但是他需要2.2秒才触发,这时候就会进入这个条件
      if (remaining <= 0 || remaining > wait) {
        // 如果存在定时器就清理掉否则会调用二次回调
        if (timeout) {
          clearTimeout(timeout);
          timeout = null;
        }
        previous = now;
        result = func.apply(context, args);
        if (!timeout) context = args = null;
      } else if (!timeout && options.trailing !== false) {
        // 判断是否设置了定时器和 trailing
	    // 没有的话就开启一个定时器
        // 并且不能不能同时设置 leading 和 trailing
        timeout = setTimeout(later, remaining);
      }
      return result;
    };
  };

防抖和节流的区别

防抖:防止抖动,单位时间内事件触发会被重置,避免事件被触发多次,重在清零
节流:控制流量,单位时间内事件只能触发一次,重在开关锁

scroll 事件下的区别

视频参考

mousemove 事件下的区别

视频参考

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/487498.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Node 10 接口

接口 简介 接口是什么 接口是 前后端通信的桥梁 简单理解&#xff1a;一个接口就是 服务中的一个路由规则 &#xff0c;根据请求响应结果 接口的英文单词是 API (Application Program Interface)&#xff0c;所以有时也称之为 API 接口 这里的接口指的是『数据接口』&#…

企业如何通过CRM系统有效触达客户,获取潜在商机

“守株待兔”式坐等客户上门的时代了已经过去了&#xff0c;尤其是在存量时代&#xff0c;企业想要提高销售&#xff0c;扩大客源&#xff0c;就要不断的通过各种渠道来去拓展自己的客户和销路&#xff0c;而互联网时代&#xff0c;获客的渠道也丰富多样&#xff0c;企业选择好…

权威重磅:全球区块链专利状况研究

文 | 国家知识产权局知识产权发展研究中心 区块链&#xff08;Blockchain&#xff09;是一种安全共享的去中心化的数据账本。近年来&#xff0c;区块链与大数据、云计算、人工智能、5G等新一代信息技术快速融合发展&#xff0c;应用已延伸到数字金融、物联网、智能制造、供应链…

Java面试题总结 | Java面试题总结11- Spring模块(持续更新)

Spring 文章目录 Spring什么是SpringSpringMVC、Spring、SrpingBoot的区别SSM和SpringBoot的区别IOC容器Spring Boot Starter有什么用SpringBoot启动原理说说你对AOP的理解spring用到的设计模式Spring是怎么解决循环依赖的&#xff1f;说说你对MVC的理解spring mvc执行流程什么…

CRM系统云部署和本地部署的优缺点有哪些

CRM客户管理系统有两种部署方式&#xff0c;分别是本地部署和云端部署。每一种部署方式都有相应的优势和劣势。下面我们就来说说&#xff0c;CRM本地部署和CRM云部署有哪些区别&#xff1f; 本地部署 CRM本地部署是指将CRM软件安装在企业自己的服务器上&#xff0c;这些服务器…

做电商数据分析可视化,这个国产BI软件很香

电商数据分析的数据采集整合工作量大&#xff0c;对实时性要求高&#xff0c;特别是跨境电商物流周期长不利于做库存计划不说&#xff0c;还容易出现运营、物流、财务、生产信息脱节等情况。难&#xff0c;但难不倒国产BI软件。在国内外BI软件中&#xff0c;国产BI软件明显更具…

php用一个单页读取数据库中带有超链接的内容并提供人工清理链接的功能(超链接部分可替换为任何查询条件)/ 代码拿去用

起因 某客户安全报告提示有一个过期网站的链接&#xff0c;且该过期网站变成了羞羞网站~~这个问题是他们平时发文的时候直接复制了别的网站内容&#xff0c;又没有用编辑器的清理工具导致的。事后&#xff0c;客户提出能不能把所有内容都查一遍&#xff0c;并去掉所有链接&…

风控系统就该这么设计(万能通用),那是相当稳定

一、背景 1.为什么要做风控? 2.为什么要自己写风控? 3.其它要求 二、思路 1.风控规则的实现 2.调用方式的实现 三、具体实现 1.风控计数规则实现 2.注解的实现 四、测试一下 1.写法 2.Debug看看 一、背景 1.为什么要做风控? 这不得拜产品大佬所赐&#xff0c;我们…

分享:集群吞吐量以1抵5,车企MySQL八大痛点的解决方案

本文来自社区分享&#xff0c;仅限交流探讨。原文作者&#xff1a;李婵玲&#xff0c;某智能车企DBA。欢迎访问 OceanBase 官网获取更多信息&#xff1a;https://www.oceanbase.com/ 最近一年&#xff0c;我们完成了从MySQL到OceanBase的替代过程&#xff0c;既降低了架构复杂度…

PostgreSQL 基础知识:psql 入门

PostgreSQL 有一个单独的命令行工具psql&#xff0c;该工具已经使用了几十年&#xff0c;并且包含在任何 PostgreSQL 安装中。许多 PostgreSQL 的长期用户、开发人员和管理员都依赖它来帮助他们快速连接到数据库、检查模式和执行 SQL 查询。 了解如何安装和使用基本psql命令是…

【每日一题】

文章目录 C 技术点多边三角形剖分的最低得分&#xff08;dp思路&#xff0c;选不选问题&#xff09;移动石子到连续&#xff08;思路&#xff09; C 技术点 1. string类型使用find函数。 int index s.find(""); if (inde ! string:npos){ xx }2. transform函数&…

[代码随想录]二叉树

二叉树 文章目录 二叉树1. 二叉树的递归遍历144.前序遍历94.中序遍历145.后续遍历 *2.二叉树的迭代遍历145.前序遍历94.中序遍历145.后续遍历 3.统一二叉树迭代遍历144.前序遍历94.中序排序145.后序遍历 4.层序遍历102.二叉树的层序遍历107. 二叉树的层序遍历 II199. 二叉树的右…

[Dev‘Life] Dubai工签指南

Dubai工作签证一般为两年有效期&#xff0c;主要流程为 PCR-TEST-REPORT&#xff08;体检&#xff09;劳动者通识培训(听课)申请ID (录制指纹/掌静脉) 前置查询&#xff1a;Dubai-ICA官网查看签证有效期 免费查询签证的状态&#xff0c;相关查询连接在此&#xff1a; https://…

与伙伴同行,Serverless 让创新触手可及

今天 Serverless 的方式真正意义上做到了云产品、云技术的开箱即用&#xff0c;企业和开发者不需要再关注底层的资源配置&#xff0c;更多地把精力放在业务系统的开发中。 4 月 26 日&#xff0c;在 2023 阿里云合作伙伴大会现场&#xff0c;阿里云智能 CTO 周靖人发表主题演讲…

XML解析(DOM4j)检索(Xpath)

XML在以后更多的是用来作为配置文件的。 一. 配置文件 什么是配置文件 用来保存程序在运行时需要的一些参数。 当配置信息比较复杂的时候&#xff0c;我们就可以用XML。 二. XML概述 三. XML的创建、语法规则 根标签就是写在最外面的标签。 <?xml version"1.0&quo…

【Unity3D小功能】Unity3D中实现Text显示版本功能

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 在项目开发中&#xff0c;会遇到要控制版本的情况&#xff0c;…

Python基础篇

大家好&#xff0c;我是易安&#xff01; Python语言比起C、Java等主流语言&#xff0c;语法更简洁&#xff0c;也更接近英语&#xff0c;对编程世界的新人还是很友好的&#xff0c;这也是其显著优点。最近总有人问我Python相关的问题&#xff0c;这些问题也偏基础&#xff0c;…

Qt绘图类

Qt绘图类 QPainter绘图1&#xff0e;QPainter与QPaintDevice2&#xff0e;paintEvent事件和绘图区3&#xff0e;QPainter绘图的主要属性4&#xff0e;创建实例 QPen的主要功能1&#xff0e;线条样式2&#xff0e;线条端点样式3. QBrush的主要功能4. 渐变填充 5 QPainter绘制…

Python小姿势 - Python连接MySQL数据库

Python连接MySQL数据库 Python是一种解释型、面向对象、动态数据类型的高级程序设计语言。 Python的创始人为吉多范罗苏姆&#xff08;Guido van Rossum&#xff09;&#xff0c;于1989年底圣诞节期间&#xff0c;为了打发无聊的圣诞节&#xff0c;决心开发一个新的脚本解释程序…

云表无代码开发平台,助力制造业练就数字化转型"硬功"

制造业作为国民经济的基础&#xff0c;也是我国的支柱产业&#xff0c;对我国经济发展具有重要意义。但随着近年来我国制造业转型升级步伐的加快&#xff0c;我国制造业在发展过程中也面临着许多困难和挑战。比如&#xff1a;企业生产设备老化、生产过程自动化程度低、产品质量…