JavaScript专题(三)防抖

news/2024/12/13 2:46:59/

防抖

目录

  • 一、为什么需要防抖
  • 二、防抖的原理
  • 三、防抖简单实现
  • 四、防抖进阶
  • 写在最后

一、为什么需要防抖

  • 高频的函数操作可能产生不好的影响
  • 如:resize、scroll、mousedown、mousemove、keyup、keydown……

为此,我们举个示例代码来了解事件如何频繁的触发:

我们写一个 index.html 文件:

<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title><title>debounce</title><style>#wrapper {width: 100%;height: 200px;line-height: 200px;text-align: center;color: #fff;background-color: #444;font-size: 30px;}</style>
</head>
<body><div id="wrapper"></div><script>var count = 1;var oDiv = document.getElementById("wrapper");function getUserAction() {oDiv.innerHTML = count++;}oDiv.onmousemove = getUserAction;</script>
</body>
</html>

从左边滑到右边就触发了近100次getUserAction 函数!看如下Gif:

在这里插入图片描述

因为这个例子很简单,所以浏览器完全反应的过来,但假设:

  • 它的触发频次极高,1分钟2000次,且涉及到大量的位置计算、DOM 操作等工作,
  • 存在接口请求,单个函数执行时间较长,但每个函数触发的间隔很近。

这种在一瞬间(短时间内)对浏览器或服务器造成了过多压力的交互就需要进行优化了,为了解决这个问题,一般有两种解决方案:

  • debounce 防抖
  • throttle 节流

他们的目的都是:降低一个函数的触发频率,以提高性能或避免资源浪费。

二、防抖的原理

今天重点讲讲防抖的实现。

防抖的原理就是:你尽管触发事件,但是我一定在事件触发n秒无操作后才执行。举个例子:

我们规定3s为防抖的标准,那么:

  1. 第一次要求执行事件 - 此时倒计时3s
  2. 倒计时2s
  3. 倒计时1s
  4. 0.5s时事件再次被触发 - 此时倒计时3s
  5. …3s内无事发生
  6. 执行事件,共用了5.5s

三、自己实现一个防抖

3.1 第一版

我们根据上一节提到的核心思想,实现第一版代码:

function debounce(func, wait) {var timer;return function () {clearTimeout(timer)timer = setTimeout(func, wait);}
}

如果我们要使用它,第一节的例子为例:

oDiv.onmousemove = debounce(getUserAction, 2000);

此时大家可以再次测试一下,事件持续发生时,只有在完全停止2s后,才会触发事件:

写到这里,作为针对部分高频事件的需求来说,已经结束了。我们来看看他的效果:

在这里插入图片描述

3.2 第二版

大家都知道,dom节点在触发事件的时候,this指向它本身,本例中则指向oDiv,但是在本例中:我们看一下

var count = 1;
var oDiv = document.getElementById("oDiv");function getUserAction() {oDiv.innerHTML = count++;console.log('this', this); // 此时输出 Window...
}
oDiv.onmousemove = debounce(getUserAction, 2000);function debounce(func, wait) {var timer;return function () {clearTimeout(timer)timer = setTimeout(func, wait);}
}

毕竟经过了一层匿名函数的包裹,this已经指向了window,为了减少影响,我们尝试修正它

function debounce(func, wait) {var timer;return function () {var _this = this; // 记录当前thisclearTimeout(timer)timer = setTimeout(function(){func.apply(_this); //将 func的this改为_this}, wait);}
}

第三版

解决的this指向问题,我们的函数仍然不够“完美”,JavaScript中,事件处理函数会提供event对象,我们简称为e。

// 使用了 debouce 函数
function getUserAction(e) {console.log(e); // undefinedoDiv.innerHTML = count++;
};

为了保证它的原汁原味,我们再改第三版:

var count = 1;
var oDiv = document.getElementById("oDiv");function getUserAction(e) {oDiv.innerHTML = count++;console.log('e', e); // MouseEvent
}
oDiv.onmousemove = debounce(getUserAction, 2000);function debounce(func, wait) {var timer;return function () {var _this = this; // 记录当前thisvar arg = arguments; // 记录参数clearTimeout(timer)timer = setTimeout(function () {func.apply(_this, arg); //将 func的this改为_this}, wait);}
}

到此为止,我们在尽可能保留Dom事件原有能力的情况下,给函数加上了防抖效果,它可以解决大部分我们日常开发的防抖问题,但我们需要更“完美”

四、防抖进阶

4.1 立即执行

这个需求就是:

  • 立即执行
  • 保持n秒空白期
  • n秒空白期置后

想想这个需求也是很有道理的嘛,那我们加个immediate参数判断是否是立刻执行。

function debounce(func, wait, immediate) {var timer;return function () {var _this = this;var args = arguments;if (timer) clearTimeout(timer); // 常规流程,间隔内触发时清掉重置定时if (immediate) {// 如果已经执行过,不再执行var callNow = !timer; // 1. callNow 初始值是 true, 同步立即执行;随后 timer 才开始执行timer = setTimeout(function(){timer = null; // wait 期间,timer 是一个 ID 数字,所以 callNow 为 false,func 在此期间永远不会执行}, wait) // wait 之后,timer 赋值 null,callNow 为 true,func 又开始立即执行。if (callNow) func.apply(_this, args)}else {timer = setTimeout(function(){func.apply(_this, args)}, wait);}}
}

再来看下此时他是什么效果:

在这里插入图片描述

4.2 添加简单验证

function debounce(func, wait, immediate) {var timer;// 检查函数if (typeof func !== 'function') {throw new TypeError('Expected a function');}// 保证wait存在wait = +wait || 0;const debounced = function () {var _this = this;var args = arguments;if (timer) clearTimeout(timer); // 常规流程,间隔内触发时清掉重置定时if (immediate) {// 如果已经执行过,不再执行var callNow = !timer; // 如果不存在定时器,则callNow为truetimer = setTimeout(function () {timer = null; // 为了保证之后的时效性,手动添加timer}, wait)// 因为不存在timer,证明是首次执行,所以直接调用if (callNow) func.apply(_this, args)}else {timer = setTimeout(function () {func.apply(_this, args)}, wait);}}return debounced
}

4.3 添加取消事件方法

如果你希望能取消被防抖的事件,我们可以这样写:

function debounce(func, wait, immediate) {var timer;// 检查函数if (typeof func !== 'function') {throw new TypeError('Expected a function');}// 保证wait存在wait = +wait || 0;const debounced = function () {var _this = this;var args = arguments;if (timer) clearTimeout(timer); // 常规流程,间隔内触发时清掉重置定时if (immediate) {// 如果已经执行过,不再执行var callNow = !timer; // 如果不存在定时器,则callNow为truetimer = setTimeout(function () {timer = null; // 为了保证之后的时效性,手动添加timer}, wait)// 因为不存在timer,证明是首次执行,所以直接调用if (callNow) func.apply(_this, args)}else {timer = setTimeout(function () {func.apply(_this, args)}, wait);}}const cancel = function(){clearTimeout(timer);timer = null;}const pending = function(){return timer !== undefined;}debounced.cancel = cancel;debounced.pending = pending;return debounced
}

我们再来看看效果:

在这里插入图片描述

写到这里这个简单的防抖方法就算OK了,它确实还不算完美,如果在改进上有任何建议,不妨在评论区留言吧~

参考

  • 冴羽大佬的Js系列
  • lodash.js

写在最后

JavaScript系列:

  1. 《JavaScript内功进阶系列》(已完结)
  2. 《JavaScript专项系列》(持续更新)

关于我

  • 花名:余光(沉迷JS,虚心学习中)
  • WX:j565017805

其他沉淀

  • Js版LeetCode题解
  • 前端进阶笔记
  • 我的CSDN博客

如果您看到了最后,对文章有任何建议,都可以在评论区留言~

如果真的对您有所帮助,也希望您能本系列的GitHub仓库,传送门点个star,这是对我最大的鼓励 !


http://www.ppmy.cn/news/480342.html

相关文章

防抖的详细解读

防抖的详细解读 场景例子说明+代码实现不运用防抖运用防抖(逐渐优化)版本一:(基本效果)版本二:(this问题)版本三:(enent对象问题)版本四:(立即执行)版本五:(返回值)版本六:(撤销操作)场景 滚动条的滚动网络请求mousemove…总之一个事件频繁的触发,而我们恰…

前端必会——防抖

目录 前言一、什么是防抖&#xff1f;二、防抖解决了什么问题三、实现防抖的基本代码四、防抖的应用场景1.代码实现2.结果展示 总结 前言 本文讲解一下js中防抖思想&#xff0c;下方有实现防抖的基本代码&#xff0c;可以复制到自己的编辑器看看效果哦。也有实际的应用场景&am…

防抖云台-鸡头稳定 简介篇

概念 EIS Electronic Image Stabilization 电子图像防抖 AIS (HUAWEI) AI Image Stabiliza 华为AI防抖 OIS Optical Image Stabilization 光学图像防抖 简介 Chicken Head Tracking 视频 原理 转自 松鼠会 与 果壳 当鸽子抬起后脚往前走&#xff0c;重心随着身体紧跟…

图像视频防抖

视频防抖 该项技术关键字挺多的&#xff0c;但作用都是去除视频拍摄过程中轻微抖动造成的图像模糊。 Anti-Shake&#xff0c;Shake-proof, imagestabilization都是这个意思&#xff0c;image stabilization是由canon最先开始这么称呼的&#xff0c;Anti-shake更通用一点。 该…

防抖、节流的介绍

目录 一、什么时候要用到防抖节流 输入框连续输入的案例 滚动条案例 二、什么是防抖、节流 使用防抖来解决输入框案例造成的浪费现象&#xff1a; 使用节流来解决滚动条案例造成的浪费现象&#xff1a; 三、总结 一、什么时候要用到防抖节流 针一类类快速连续触发和不可控…

视频防抖技术的实现

1. 介绍 视频防抖是指用于减少摄像机运动对最终视频的影响的一系列方法。摄像机的运动可以是平移&#xff08;比如沿着x、y、z方向上的运动&#xff09;或旋转&#xff08;偏航、俯仰、翻滚&#xff09;。 对视频防抖的需求在许多领域都有。 这在消费者和专业摄像中是极其重…

EIS(电子稳像,视频防抖)算法开发记录

最近项目中有个小需求&#xff0c;需要对运动视频使用电子稳像算法进行稳像处理。开发从0开始&#xff0c;在此记录一下开发过程和心得&#xff0c;做个备份&#xff0c;期间也走了很多弯路&#xff0c;供大家参考。最终效果个人认为基本可媲美主流手机。先上最终效果&#xff…

光学防抖OIS介绍与标定

1.开篇直接先看一下有无OIS的效果差异 手持设备拍照时,手的抖动(点击抖动和生理抖动)会造成相机的轻微倾斜(一般在+/-0.5度以内),该倾斜引起了镜头观察角度的变化,以镜头为参照物来说,相当于被拍摄的物体移动了,因此所成的像也会在图像传感器上相对于原位置发生偏移, 结果造成图…