温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

JavaScript中防抖的示例分析

发布时间:2021-03-04 13:58:23 来源:亿速云 阅读:213 作者:小新 栏目:web开发

这篇文章给大家分享的是有关JavaScript中防抖的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。

JavaScript的特点

1.JavaScript主要用来向HTML页面添加交互行为。 2.JavaScript可以直接嵌入到HTML页面,但写成单独的js文件有利于结构和行为的分离。 3.JavaScript具有跨平台特性,在绝大多数浏览器的支持下,可以在多种平台下运行。

一、为什么需要防抖

  • 高频的函数操作可能产生不好的影响

  • 如: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>     <p id="wrapper"></p>     <script>         var count = 1;         var op = document.getElementById("wrapper");         function getUserAction() {             op.innerHTML = count++;         }         op.onmousemove = getUserAction;     </script></body></html>

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

JavaScript中防抖的示例分析

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

  • 它的触发频次极高,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);     }}

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

op.onmousemove = debounce(getUserAction, 2000);

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

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

JavaScript中防抖的示例分析

3.2 第二版

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

var count = 1;var op = document.getElementById("op");function getUserAction() {     op.innerHTML = count++;     console.log('this', this); // 此时输出 Window...}op.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; // 记录当前this         clearTimeout(timer)         timer = setTimeout(function(){             func.apply(_this); //将 func的this改为_this         }, wait);     }}
第三版

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

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

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

var count = 1;var op = document.getElementById("op");function getUserAction(e) {     op.innerHTML = count++;     console.log('e', e); // MouseEvent}op.onmousemove = debounce(getUserAction, 2000);function debounce(func, wait) {     var timer;     return function () {         var _this = this; // 记录当前this         var 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);         }     }}

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

JavaScript中防抖的示例分析

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为true             timer = 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为true             timer = 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}

我们再来看看效果:

JavaScript中防抖的示例分析

感谢各位的阅读!关于“JavaScript中防抖的示例分析”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI