javaScript中的函数防抖和节流

什么是函数防抖和节流

JavaScript 中的函数大多数情况下都是由用户主动调用触发的,除非是函数本身的实现不合理,否则一般不会遇到跟性能相关的问题。

但是在一些少数情况下,函数的触发不是由用户直接控制的。在这些场景下,函数有可能被非常频繁地调用,而造成大的性能问题。解决性能问题的处理办法就有函数防抖函数节流

下面是函数被频繁调用的常见的几个场景:

  • mousemove 事件:如果要实现一个拖拽功能,需要一路监听 mousemove 事件,在回调中获取元素当前位置,然后重置 DOM 的位置来进行样式改变。如果不加以控制,每移动一定像素而触发的回调数量非常惊人,回调中又伴随着 DOM 操作,继而引发浏览器的重排与重绘,性能差的浏览器可能就会直接假死。
  • window.onresize 事件:为 window 对象绑定了 resize 事件,当浏览器窗口大小被拖动而改变的时候,这个事件触发的频率非常之高。如果在 window.onresize 事件函数里有一些跟 DOM 节点相关的操作,而跟 DOM 节点相关的操作往往是非常消耗性能的,这时候浏览器可能就会吃不消而造成卡顿现象。
  • 射击游戏的 mousedown/keydown 事件(单位时间只能发射一颗子弹)
  • 搜索联想(keyup 事件)
  • 监听滚动事件判断是否到页面底部自动加载更多(scroll 事件)

对于这些情况的解决方案就是函数防抖(debounce)或函数节流(throttle),其核心就是限制某一个方法的频繁触发

函数防抖

函数防抖,是指防止函数在极短的时间内反复调用,造成资源的浪费

考虑一个页面上的场景,页面上的某些事件触发频率非常高,比如滚动条滚动、窗口尺寸变化、鼠标移动等,如果我们需要注册这类事件,不得不考虑效率问题,又特别是事件处理中涉及到了大量的操作,比如:

window.onresize = function(){
    // 大量的 DOM 操作
}

当窗口尺寸发生变化时,哪怕只变化了一点点,都有可能造成成百上千次对处理函数的调用,这对网页性能的影响是极其巨大的。

于是,我们可以考虑,每次窗口尺寸变化、滚动条滚动、鼠标移动时,不要立即执行相关操作,而是等一段时间,以窗口尺寸停止变化、滚动条不再滚动、鼠标不再移动为计时起点,一段时间后再去执行操作,就像生活中电梯关门那样。

于是,为了满足这种类型场景,我们可以开发一个通用的函数,这个函数要满足以下功能:

  1. 调用该函数后,不立即做事,而是一段时间后去做事
  2. 如果在等待时间内又调用了该函数,则重新计时

这样的功能,就叫做函数防抖,其实就是防止函数短时间内被调用多次。

要完成该函数,需要给予两个条件:

  1. 告诉我一段时间后要做什么事(这里应该是一个回调函数,即函数作为参数)
  2. 告诉我要等待多长时间(毫秒)

下面我们就来封装这么一个函数防抖的通用函数:

/**
 * 函数防抖
 * @param {function} func 一段时间后,要调用的函数
 * @param {number} wait 等待的时间,单位毫秒
 */
function debounce(func, wait) {
    // 设置变量,记录 setTimeout 得到的 id
    var timerId = null;
    return function (...args) {
        if (timerId) {
            // 如果有值,说明目前正在等待中,清除它
            clearTimeout(timerId);
        }
        // 重新开始计时
        timerId = setTimeout(() => {
            func(...args);
        }, wait);
    }
}

下面来进行一个测试,测试如下:

<input type="text" id="txt">
var txt = document.getElementById("txt");
// 调用 debounce 函数来将事件处理函数变为一个防抖函数
var debounceHandle = debounce(function(event){
  console.log(event.target.value);
}, 500)
txt.onkeyup = (event)=>{
  debounceHandle(event);
}

函数节流

函数节流的目的,也是为了防止一个函数短时间内被频繁的触发。

和函数防抖的原理不同,函数节流的核心思想是让连续的函数执行,变为固定时间段间断地执行。

这里我们要介绍的函数节流,指一定时间内函数只执行一次。比如人的眨眼睛,就是一定时间内眨一次。这是函数节流最形象的解释。

关于节流的实现,有 2 种主流的实现方式,一种是使用时间戳,一种是设置定时器

(1)使用时间戳

触发事件时,取出当前的时间戳,然后减去之前的时间戳(最一开始值设为 0),如果大于设置的时间周期,就执行函数,然后更新时间戳为当前的时间戳,如果小于,就不执行。

下面是封装使用时间戳的函数节流的通用函数:

/**
 * 
 * @param {要进行节流的函数} func 
 * @param {间隔时间} wait 
 * @returns 
 */
function throttle(func, wait) {
    var args; // 存储函数参数
    var previous = 0; // 一开始的默认时间
    return function () {
        var now = new Date(); // 获取最新的时间戳
        args = arguments; // 获取参数
        // 进行时间戳的判断,如果超出规定时间,则执行
        if (now - previous > wait) {
            func.apply(null, args);
            previous = now;
        }
    }
}

下面来实际使用测试一下:

<input type="text" id="txt">
var txt = document.getElementById("txt");
// 调用 throttle 函数来将事件处理函数变为一个节流函数
var throttleHandle = throttle(function (event) {
  console.log(event.target.value);
}, 1000)
txt.onkeyup = (event) => {
  throttleHandle(event);
}

(2)设置定时器

第二种方式是设置定时器,触发事件时设置一个定时器,再触发事件的时候,如果定时器存在,就不执行,直到定时器执行,然后执行函数,清空定时器,这样就可以设置下个定时器。

下面是封装使用定时器的函数节流的通用函数:

/**
 * 
 * @param {要节流执行的函数} func 
 * @param {节流的时间间隔} wait 
 * @returns 
 */
function throttle(func, wait) {
    // timeout 存储计时器返回值
    // args 存储参数
    var timeout, args;
    return function () {
        args = arguments;
        // 如果 timeout 有值,说明上一次的执行间隔时间还没过
        if (!timeout) {
            // 进入此 if 说明时间间隔已经过了
            // 先执行一次要执行的函数
            func.apply(null, args)
            // 然后重新设置时间间隔
            timeout = setTimeout(function () {
                timeout = null;
            }, wait);
        }
    }
}

其他参考:实现一个防抖函数、完善一个防抖函数

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

虚拟机软件哪个好用 虚拟机软件哪个可以玩暗区突围 虚拟机软件排名 PD19虚拟机 Mac类虚拟机运行Windows程序 CrossOver支持的热门游戏

随着跨系统互联的需求不断增长&#xff0c;越来越多的用户会选择在电脑系统中安装虚拟机软件&#xff0c;进而更加便捷地访问和操作其他系统。一款好用的虚拟机软件能够提高系统互联的效率&#xff0c;进而实现了资源共享、测试环境搭建等多种用途。而在众多的虚拟机软件当中&a…

张驰咨询:降本增效企业突破市场重围的制胜法宝

企业在快速发展的过程中&#xff0c;降本增效是永恒不变的主题。毕竟&#xff0c;在竞争激烈的市场环境中&#xff0c;只有不断提高效率和降低成本&#xff0c;才能在竞争中立于不败之地。那么&#xff0c;为什么企业需要降本增效呢&#xff1f; 首先&#xff0c;降本增效是企业…

vue+springboot的登录图片验证码(前端对接报错)

tip:这个只是一个效果实际要运用&#xff0c;还是需要改改滴&#xff01; 后台Java自带的 本来我是打算用第三方库的&#xff0c;没有整出来&#xff0c;就跟沈某人说不会来着&#xff0c;他说最好用Java自带的&#xff0c; 不然换个系统第三方的就不能用了&#xff0c;大概…

不可以论文查重,也包含了查AI率吗?

临近毕业&#xff0c;完成一篇符合学术规范的毕业论文是一项繁琐又具挑战性的任务。撰写完论文后&#xff0c;反复的查重降重已让人心身疲累。今年&#xff0c;学校又提出了新要求&#xff0c;论文还需要通过AIGC检测系统&#xff08;www.checkaigc.com&#xff09;才行&#x…

Vue2学习笔记(尚硅谷天禹老师)

目录 一、入门案例 二、模板语法 三、数据绑定 四、el和data的两种写法 五、MVVM模型 六、Object.defineproperty方法 七、Vue中响应式原理 八、数据代理 九、methods配置项 十、Vue中的事件处理 十一、Vue中的键盘事件 十二、计算属性 十三、监视属性watch 十四、绑定Class样式…

【echarts】数据起点不从X轴的原点开始【不从0开始】

echarts折线图x轴不从0开始怎么办&#xff1f; 或者说为什么有些图是这样的 有些却是这样的 原因出在这里&#xff1a; boundaryGap: false 默认是true&#xff0c;是指坐标轴两边留白。改为false&#xff1a;不留白即从原点开始。 看一下官方的说明

中小型企业网络实战topo

1、设备命名&#xff0c;务必按照规范进行命名规划&#xff1b; 2、子网划分&#xff0c;申请到了公网地址段&#xff0c;201.1.1.0/24&#xff0c;根据公司的实际情况&#xff0c;合理规划拓扑需要的公网地址&#xff0c; 做到合理规划不浪费&#xff1b; 3、子网划分&a…

嵌入式开发学习--进程、线程

什么是进程 进程和程序的区别 概念 程序&#xff1a;编译好的可执行文件&#xff0c;存放在磁盘上的指令和数据的有序集合&#xff08;文件&#xff09;&#xff0c;程序是静态的&#xff0c;没有任何执行的概念。 进程&#xff1a;一个独立的可调度的任务&#xff0c;执行一…

做抖音小店如何选品?这几个技巧,精准“锁定”爆品!

哈喽~我是电商月月 做抖音小店最重要的就是选品&#xff0c;这点大家都知道 一个店铺商品选的好&#xff0c;顾客喜欢&#xff0c;质量完好&#xff0c;销量和售后都不用操心&#xff0c;和达人合作时&#xff0c;爆单的机会也就越高 那这种商品是什么样的&#xff0c;新手开…

基于ssm微信小程序的4S店客户管理系统

采用技术 基于ssm微信小程序的4S店客户管理系统的设计与实现~ 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringMVCMyBatis 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 页面展示效果 管理员端 管理员登录 管理员首页 用户管理 门店管理 …

RustGUI学习(iced)之小部件(一):如何使用按钮和文本标签部件

前言 本专栏是学习Rust的GUI库iced的合集&#xff0c;将介绍iced涉及的各个小部件分别介绍&#xff0c;最后会汇总为一个总的程序。 iced是RustGUI中比较强大的一个&#xff0c;目前处于发展中&#xff08;即版本可能会改变&#xff09;&#xff0c;本专栏基于版本0.12.1. 概述…

高效一键改写文章,智能伪原创工具轻松搞定

在信息爆炸的时代&#xff0c;想要高效率的一键改写文章却是很多创作者都想了解的方法。然而在人工智能技术发展的今天&#xff0c;智能伪原创工具的出现&#xff0c;也正是成了广大创作者用来一键改写文章的好方法&#xff0c;因为它的优势&#xff0c;可以为大家轻松完成改写…

光伏二次设备主要有哪些

光伏电站二次设备类型比较多&#xff0c;信息显示、数据安全、远动通信、电能质量、微机保护等都有不同设备相互配合完成&#xff0c;根据项目具体需求来选择&#xff0c;简单可以分为以下几种&#xff1a; 一、光伏二次设备保护屏&#xff1a; 1、光伏二次设备预制舱 二次设…

短视频矩阵系统源码====3年技术公司源头开发商交付

短视频矩阵系统#源头技术打磨 哈尔滨爆火带动了一波“北上热潮”&#xff0c;各地文旅坐不住了&#xff0c;兄弟们开“卷”&#xff01;这波互卷浪潮中&#xff0c;河南率先出圈。如今&#xff0c;河南文旅账号粉丝已经突破200w&#xff01; 01 矩阵打法&#xff0c;很难不火…

超越边界:如何ChatGPT 3.5、GPT-4、DALL·E 3和Midjourney共同重塑创意产业

KKAI&#xff08;kkai人工智能&#xff09;是一个整合了多种尖端人工智能技术的多功能助手平台&#xff0c;融合了OpenAI开发的ChatGPT3.5、GPT4.0以及DALLE 3&#xff0c;并包括了独立的图像生成AI—Midjourney。以下是这些技术的详细介绍&#xff1a; **ChatGPT3.5**&#xf…

Lab2: system calls

Using gdb Looking at the backtrace output, which function called syscall? 可以看到是trap.c中usertrap函数调用了syscall函数 What is the value of p->trapframe->a7 and what does that value represent? p->trapframe->a7的值为7&#xff0c;代表了函…

MATLAB 条件语句

MATLAB 条件语句 决策结构要求程序员应指定一个或多个要由程序评估或测试的条件&#xff0c;如果确定条件为真&#xff0c;则应指定要执行的一个或多个语句&#xff0c;如果条件为真&#xff0c;则可以选择要执行的其他语句。条件确定为假。 以下是大多数编程语言中常见的典型…

我们支持批量了!

当我们有很多文件要处理时&#xff0c;一个一个操作不仅费时费力&#xff0c;而且还容易漏掉某个文件。那么有没有更加简单的方法呢&#xff1f;可以试试批量功能&#xff01; 目前以下功能都支持批量操作 音频提取 视频格式转换 字幕生成 视频静音 图片格式转换 图片压缩 视频…

JavaScript —— APIs(四)

一、日期对象 1. 实例化 new 括号里面为空&#xff0c;得到当前时刻的时间 括号里面为指定日期&#xff0c;得到对应日期的时间 注意&#xff1a;若括号里面只有年月日&#xff0c;没有时间&#xff0c;则得到的结果就没有时间&#xff1b;括号里面指定时间是多少&#xff0c;…

身份证二要素核验介绍及使用方法

一、身份证二要素核验简介及重要性 身份证二要素核验是一种重要的身份验证技术&#xff0c;它在现代社会中发挥着至关重要的作用&#xff0c;特别是在涉及个人信息安全和隐私保护的领域。通过身份证二要素核验&#xff0c;我们可以有效地确认个人身份的真实性&#xff0c;从而…
最新文章