GVKun编程网logo

vue 节流throttling防抖debounce(vue节流和防抖)

10

以上就是给各位分享vue节流throttling防抖debounce,其中也会对vue节流和防抖进行解释,同时本文还将给你拓展debounce(防抖)和throttle(节流)、DebounceVsT

以上就是给各位分享vue 节流throttling防抖debounce,其中也会对vue节流和防抖进行解释,同时本文还将给你拓展debounce(防抖)和throttle(节流)、DebounceVsThrottle(防抖和节流)、JavaScript 函数节流 throttle 和防抖 debounce、JavaScript 防抖debounce与节流thorttle等相关知识,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!

本文目录一览:

vue 节流throttling防抖debounce(vue节流和防抖)

vue 节流throttling防抖debounce(vue节流和防抖)

节流和防抖常用与监听滚动事件,移动事件,窗口改变大小事件,输入事件等高频触发事件,当事件处理函数较为复杂时,将导致无法实时响应,降低用户体验度,影响效率,出现页面卡顿,假死等现象。

debounce 周期内有新事件触发,清除旧定时器,重置新定时器;这种方法,需要高频的创建定时器。

throttling 周期内有新事件触发时,重置定时器开始时间撮,定时器执行时,判断开始时间撮,若开始时间撮被推后,重新设定延时定时器。

 

1.定义模块文件并导出防抖函数和节流函数

 
  1.  
    /**
  2.  
    * 防抖函数
  3.  
    * fu 延时调用函数
  4.  
    * delay 延迟多长时间
  5.  
    */
  6.  
    export const _debounce = (fn, delayTime) => {
  7.  
    let delay = delayTime || 200;
  8.  
    let timer;
  9.  
    return function() {
  10.  
    let th = this;
  11.  
    let args = arguments;
  12.  
    if (timer) {
  13.  
    clearTimeout(timer);
  14.  
    }
  15.  
    timer = setTimeout(function() {
  16.  
    timer = null;
  17.  
    fn.apply(th, args);
  18.  
    }, delay);
  19.  
    };
  20.  
    };
  21.  
     
  22.  
    /**
  23.  
    * 节流函数
  24.  
    * fu 延时调用函数
  25.  
    * delay 延迟多长时间
  26.  
    * atleast 至少多长时间触发一次
  27.  
    */
  28.  
    export const _throttle = (fn, delay, atleast) => {
  29.  
    let timer = null
  30.  
    let previous = null
  31.  
    return function() {
  32.  
    let now = +new Date()
  33.  
    if (!previous) previous = now
  34.  
    if (atleast && now - previous > atleast) {
  35.  
    fn()
  36.  
    previous = now
  37.  
    clearTimeout(timer)
  38.  
    } else {
  39.  
    clearTimeout(timer)
  40.  
    timer = setTimeout(function() {
  41.  
    fn()
  42.  
    previous = null
  43.  
    }, delay)
  44.  
    }
  45.  
    }
  46.  
    };

2.在组件中导入函数

 
  1.  
    import {
  2.  
    _throttle,
  3.  
    _debounce
  4.  
    } from ''@/common/config/debThr.js'';

3.methods中调用

 
  1.  
    methods: {
  2.  
    _throttle,
  3.  
    _debounce,
  4.  
    querySearchAsync() {
  5.  
    this._debounce(this.testFun, 1000)()
  6.  
    },
  7.  
    handleSelect(item) {
  8.  
    console.log(item);
  9.  
    },
  10.  
    testFun() {
  11.  
    console.log(''输入框触发了:'' + `${this.count++}...${this.test}`, new Date());
  12.  
    }
  13.  
    }

4.模版

 
  1.  
    <el-form-item lable="节流防抖">
  2.  
    <el-autocomplete v-model="test" :fetch-suggestions="querySearchAsync" placeholder="节流防抖" @select="handleSelect"></el-autocomplete>
  3.  
    </el-form-item>

 

debounce(防抖)和throttle(节流)

debounce(防抖)和throttle(节流)

防抖和节流

窗口的resizescroll,输入框内容校验等操作时,如果这些操作处理函数较为复杂或页面频繁重渲染等操作时,如果事件触发的频率无限制,会加重浏览器的负担,导致用户体验非常糟糕。此时我们可以采用debounce(防抖)和throttle(节流)的方式来减少触发的频率,同时又不影响实际效果。

debounce 防抖

debounce(防抖),简单来说就是防止抖动。

debounce 防抖

从上图中我们可以看到,当持续触发事件时,debounce会合并事件且不会去触发事件,当一定时间内没有触发再这个事件时,才真正去触发事件~ 一起来实现个简单的debounce:

function debounce(fn, delay) {
  var ctx;
  var args;
  var timer = null;

  var later = function () {
    fn.apply(ctx, args);
    // 当事件真正执行后,清空定时器
    timer = null;
  };

  return function () {
    ctx = this;
    args = arguments;
    // 当持续触发事件时,若发现事件触发的定时器已设置时,则清除之前的定时器
    if (timer) {
      clearTimeout(timer);
      timer = null;
    }

    // 重新设置事件触发的定时器
    timer = setTimeout(later, delay);
  };
}

效果图:

sample debounce

throttle 节流

throttle(节流),当持续触发事件时,保证隔间时间触发一次事件。

throttle 节流

上图中绿色块表示触发一次事件,持续触发事件时,throttle会合并一定时间内的事件,并在该时间结束时真正去触发一次事件~ 一起来看看throttle的简单实现:

function throttle(fn, delay) {
  var ctx;
  var args;
  // 记录上次触发事件
  var previous = Date.now();

  var later = function () {
    fn.apply(ctx, args);
  };

  return function () {
    ctx = this;
    args = arguments;
    var now = Date.now();
    // 本次事件触发与上一次的时间比较
    var diff = now - previous - delay;

    // 如果隔间时间超过设定时间,即再次设置事件触发的定时器
    if (diff >= 0) {
      // 更新最近事件触发的时间
      previous = now;
      setTimeout(later, delay);
    }
  };
}

效果图:

sample throttle

总结

根据实际业务场景,合理的利用debounce(防抖)和throttle(节流)可以优化性能和提高用户体验。两者间的核心区别就在于持续触发事件时,前者合并事件并在最后时间去触发事件,而后者则是隔间时间触发一次~

关键知识点

setTimeout 定时器

w3school

Closure 闭包

ruanyifeng

资源

在线测试

源代码

DebounceVsThrottle(防抖和节流)

DebounceVsThrottle(防抖和节流)

本人原文

不从概念触发,先从应用讲起。如果要你设计一个输入搜索组件,你会怎么做。可能你觉得很简单,响应输入框的 keydown 和 change 事件,然后向服务器发起请求就可以了。这样的处理方案思路上是没毛病的,不过会存在两个问题,分别影响客户端和服务器。

  1. 过于频繁的响应事件,会降低用户体验。
  2. 过于频繁的请求服务器,增加服务器压力。

我们先思考一下用户增加、删除一个字符就发起请求的合理性。一般而言,搜索单个字符对于用户来说是没有意义的,用户往往是需要搜索一个单词或者短语。那么使用以上的设计,在用户输入他想要搜索的文字之前的所有搜索,都是浪费的请求。同时,过于频繁的处理事件,当事件响应变多了之后,页面会出现卡顿也是理所当然的事。另外,对于服务器而言,搜索一般来说本身就是比较复杂、耗时的服务,过多的请求不可避免地增加服务器的并发量更是给服务器增加压力。

从以上的简单分析可以知道,我们并不需要对用户的输入进行立马响应,可以等待用户输入停止之后再进行实际的逻辑处理,这样的设计也是更符合用户体验的。

这样的想法就是所谓的防抖,而另一个相似的做法是节流。他们的区别是,防抖是在最后一次事件触发后等待一定的时间再做逻辑处理,如果在这个等待时间结束之前有新的事件发生,那么这个事件就是最后一次事件,逻辑处理的时机也要相应往后延;而节流是每隔一定时间就做一次逻辑处理。他们的共同点都是降低逻辑处理的频率。

简单的防抖代码如下

function debounce(func, timespan) {
  let timer;

  return function () {
    const context = this;
    const args = arguments;

    clearTimeout(timer);
    timer = setTimeout(() => {
      func.apply(context, args);
    }, timespan);
  };
}

简单的节流代码如下

function throttle(func, timespan) {
  let running = false;
  let context;
  let args;

  return function () {
    context = this;
    args = arguments;

    if (!running) {
      running = true;
      setTimeout(() => {
        func.apply(context, args);
        running = false;
      }, timespan);
    }
  };
}

一张图来对比一下他们在时序上的区别(上边是 debounce,下边是 throttle,每个框等时长)

JavaScript 函数节流 throttle 和防抖 debounce

JavaScript 函数节流 throttle 和防抖 debounce

今天和别人聊到JavaScript函数的节流和防抖,发现自己对这两个的区别很是模糊,遂小小实践一下,在此记录,希望对需要的人有所帮助。

节流 - 频繁操作,间隔一定时间去做一件事

举例说明:假定时间间隔为 500ms,频繁不停的操作 2s,且每两次执行时间小于等于时间间隔 500ms,那么就会执行 4 次,也就是每隔 时间间隔 500ms 执行一次。

防抖 - 频繁操作,一定时间间隔内只执行最后一次操作

举例说明:假定时间间隔是 500ms,频繁不停的操作 5s,且每两次执行时间小于等于时间间隔 500ms,那么最后只执行了 1 次,也就是每一次执行时都结束了上一次的执行。

代码示例

    //节流方法 1
    function throttle1(method, duration){
        var prevTime = new Date();
        return function () {
            var context = this,
                currentTime = new Date(),
                resTime = currentTime - prevTime;
            //打印出本次调用方法和上次执行方法的时间差
            console.log("时间差"+resTime);
            //当本次调用距离上次执行方法的时间差大于等于要求时间间隔时,执行一次方法
            if(resTime >= duration){
                method.apply(context);
                //记录执行方法的时间
                prevTime = currentTime;
            }
        }
    }
    //节流方法 2
    function throttle2(method, duration){
        //当前时间间隔内是否有方法在执行(或者说方法的调用是否在进行)
        var runningFlag = false;
        return function (e) {
            // 判断当前是否有方法在执行,有,则什么都不做
            if (runningFlag) {
                return false;
            }
            //开始执行
            runningFlag = true;
            setTimeout(function(){
                method(e);
                //执行完毕,声明当前没有正在执行的方法,方便下一个时间间隔内的调用
                runningFlag = false;
            }, duration)
        }
    }
    //防抖
    function debounce(method, duration){
        var timer = null;
        return function(){
            var context = this,
                args = arguments;
            //在本次调用之前的一个间隔时间内,有方法在执行,则终止该方法的执行
            if(timer){
                clearTimeout(timer);
            }
            //开始执行本次调用
            timer = setTimeout(function(){
                method.apply(context, args);
            },duration);
        }
    }
    //模拟三个执行方法
    function jieliu1(){
        console.log("节流 1");
    }
    function jieliu2(){
        console.log("节流 2");
    }
    function fangdou(){
        console.log("防抖");
    }
    //持续执行时间
    var totalTime = 2000;

    var jieliuFn1 = throttle1(jieliu1,500);
    var jieliuFn2 = throttle2(jieliu2,500);
    var fangdouFn = debounce(fangdou,500);

    (function(duration){
        setInterval(function(){
            if( totalTime > 0 ){
                jieliuFn1();
                jieliuFn2();
                fangdouFn();
                totalTime -= duration;
            }
        },duration);
    })(100);

运行结果

时间差 100
时间差 201
时间差 303
时间差 401
时间差 504
节流 1
时间差 98
节流 2
时间差 199
时间差 300
时间差 396
时间差 496
时间差 597
节流 1
时间差 100
节流 2
时间差 203
时间差 299
时间差 402
时间差 500
节流 1
时间差 103
时间差 204
节流 2
时间差 303
时间差 400
节流 2
防抖

结论

由以上运行结果可以看出,节流1 出现了 3 次,节流2 出现了 4 次,防抖出现了 1 次。防抖实现顺利,但是两个节流方法的执行结果存在差异。
观察时间差可以看出,每次节流1 执行时,时间差并不会都是 500 整,也就是说,一共调用 2 秒时,节流1 并不能做到每隔 500 毫秒执行一次而共执行 4 次,第四次执行往往因为前面的 3 次执行的时间误差,而导致到达时间 2 秒时,最后一次的时间差无法达到 时间间隔 500ms 以上,以至于只能执行 3 次。

结论:当在一个大范围的时间内,比如两小时内,每几分钟执行一次,超过2小时则不再实行,推荐使用第一种节流方式,;如果仅仅要求间隔一定时间执行一次,推荐使用第二种节流方法;防止频繁操作,比如表单多次提交,推荐使用防抖。

如有问题,欢迎指正,谢谢!

JavaScript 防抖debounce与节流thorttle

JavaScript 防抖debounce与节流thorttle

前言:

防抖(Debounce) 和 节流(Throttle) 技术用于限制函数执行的次数。通常,一个函数将被执行多少次或何时执行由开发人员决定。但在某些情况下,开发人员会将这种能力赋予用户,由用户决定执行该功能的时间和次数。

例如,添加到clickscrollresize等事件上的函数,允许用户决定何时执行它们以及执行多少次。有时,用户可能会比所需更频繁地执行这些操作。这可能不利于网站的性能,特别是如果附加到这些事件的函数执行一些繁重的计算。在这种情况下,用户可以控制函数的执行,开发人员必须设计一些技术来限制用户可以执行函数的次数。

举个例子,假设我们为滚动事件scroll添加了一个函数,该函数中会执行修改DOM元素的操作。我们知道,修改DOM元素大小开销很大,会引起浏览器的回流(Reflow)和重排(Repaint),以及重新渲染整个或部分页面。如果用户频繁滚动,导致该函数频繁被调用,可能会影响网页性能或导致页面卡顿等。
此外,有些事件回调函数中包含ajax等异步操作的时候,多次触发会导致返回的内容结果顺序不一致,而导致得到的结果非最后一次触发事件对应的结果

所以,为了优化网页的性能,控制函数被调用的频率是很有必要的,防抖(Debounce) 和 节流(Throttle) 是通过控制函数被调用的频率来优化脚本性能的两种方法

一、防抖(Debounce)

防抖:无论用户触发多少次事件,对应的回调函数只会在事件停止触发指定事件后执行。(即:回调函数在事件停止触发指定时间后被调用)

例如,假设用户在 100 毫秒内点击了 5 次按钮。防抖技术不会让这些点击中的任何一个执行对应的回调函数。一旦用户停止点击,如果去抖时间为 100 毫秒,则回调函数将在 100 毫秒后执行。因此,肉眼看来,防抖就像将多个事件组合成一个事件一样。

1.1 防抖函数的实现

(1)版本1 —— 停止触发事件n毫秒后执行回调函数

触发事件后函数不会立即执行,而是在停止事件触发后 n 毫秒后执行,如果在 n 毫秒内又触发了事件,则会重新计时

/**
* @desc 函数防抖
* @param func 回调函数
* @param delay 延迟执行毫秒数
*/
function debounce(func, delay) {
    let timer;  // 定时器

    return function () { 
        let context = this;  // 记录 this 值,防止在回调函数中丢失
        let args = arguments;  // 函数参数

        //如果定时器存在,则清除定时器(如果没有,也没必要进行处理)
        timer ? clearTimeout(timer) : null; 

        timer = setTimeout(() => { 
            // 防止 this 值变为 window
            func.apply(context, args) 
        }, delay);
    }
} 

(2)版本2

触发事件后立即执行回调函数,但是触发后n毫秒内不会再执行回调函数,如果 n 毫秒内触发了事件,也会重新计时。

 /**
* @desc 函数防抖
* @param func 回调函数
* @param delay 延迟执行毫秒数
*/ 
function _debounce(func, delay) {
    let timer;  // 定时器

    return function () {
        let context = this;  // 记录 this 值,防止在回调函数中丢失
        let args = arguments;  // 函数参数

        // 标识是否立即执行
        let isImmediately = !timer;

        //如果定时器存在,则清除定时器(如果没有,也没必要进行处理)
        timer ? clearTimeout(timer) : null;

        timer = setTimeout(() => {
            timer = null;
        }, delay);

        // isImmediately 为 true 则 执行函数(即首次触发事件)
        isImmediately ? func.apply(context, args) : null;
    }
} 

举个例子来对比一下两个版本的区别:

document.body.onclick= debounce(function () { console.log(''hello'') },1000)

如上代码中,我们给body添加了一个点击事件监听器。

  • 如果是版本1的防抖函数,当我点击body时,控制台不会立即打印hello,要等 1000ms 后才会打印。在这 1000s 内如果还点击了 body,那么就会重新计时。即最后一次点击 body 过1000ms后控制台才会打印hello
  • 如果是版本2的防抖函数,当我首次点击body时,控制台会立马打印 hello,但是在此之后的 1000ms 内点击 body ,控制台不会有任何反应。在这 1000s 内如果还点击了 body,那么就会重新计时。必须等计时结束后再点击body,控制台才会再次打印 hello

1.2 防抖的实际应用

(1)搜索框建议项

通常,搜索框会提供下拉菜单,为用户当前的输入提供自动完成选项。但有时建议项是通过请求后端得到的。可以在实现提示文本时应用防抖,在等待用户停止输入一段时间后再显示建议文本。因此,在每次击键时,都会等待几秒钟,然后再给出建议。

(2)消除resize事件处理程序的抖动。

window 触发 resize 的时候,不断的调整浏览器窗口大小会不断触发这个事件,用防抖让其只触发一次

(3)自动保存

例如掘金一类的网站,都会内嵌文本编辑器,在编辑过程中会自动保存文本,防止数据丢失。每次保存都会与后端进行数据交互,所以可以应用防抖,在用户停止输入后一段时间内再自动保存。

(4)手机号、邮箱等输入验证检测

通常对于一些特殊格式的输入项,我们通常会检查格式。我们可以应用防抖在用户停止输入后一段时间再进行格式检测,而不是输入框中内容发生改变就检测。

(5)在用户停止输入之前不要发出任何 Ajax 请求

二、节流(Throttle)

节流:无论用户触发事件多少次,附加的函数在给定的时间间隔内只会执行一次。(即:回调函数在规定时间内最多执行一次)

 例如,当用户单击一个按钮时,会执行一个在控制台上打印Hello, world的函数。现在,假设对这个函数应用 1000 毫秒的限制时,无论用户点击按钮多少次,Hello, world在 1000 毫秒内都只会打印一次。节流可确保函数定期执行。

2.1 节流函数的实现

(1)版本1 —— 使用定时器

 /**
* @desc 函数节流
* @param func 回调函数 
* @param limit 时间限制
*/
const throttle = (func, limit) => {
    let inThrottle;  // 是否处于节流限制时间内

    return function() {
        const context = this;
        const args = arguments;

        // 跳出时间限制
        if (!inThrottle) {
            func.apply(context, args);  // 执行回调
            inThrottle = true;  
            // 开启定时器计时
            setTimeout(() => inThrottle = false, limit);
        }
    }
}

(2)版本2 —— 计算当前时间与上次执行函数时间的间隔

 /**
* @desc 函数节流
* @param func 回调函数
* @param limit 时间限制
*/ 
function throttle(func, limit) {
    //上次执行时间
    let previous = 0;
    return function() {
        //当前时间
        let now = Date.now();

        let context = this;
        let args = arguments;

        // 若当前时间-上次执行时间大于时间限制
        if (now - previous > limit) {
            func.apply(context, args);
            previous = now;
        }
    }
} 

很多现有的库中已经实现了防抖函数和节流函数

2.2 节流的实际应用

(1)游戏中通过按下按钮执行的关键动作(例如:射击、平A)

拿王者荣耀为例,通常都有攻速一说。如果攻速低,即使 n 毫秒内点击平A按钮多次,也只会执行一次平A。其实这里就类似于节流的思想,可以通过设置节流的时间间隔限制,来改变攻速。

(2)滚动事件处理

如果滚动事件被触发得太频繁,可能会影响性能,因为它包含大量视频和图像。因此滚动事件必须使用节流

(3)限制mousemove/touchmove事件处理程序

小结

如何选择防抖和节流:

关于防抖函数和节流函数的选择,一篇博客中是这样建议的:

A debounce is utilized when you only care about the final state. A throttle is best used when you want to handle all intermediate states but at a controlled rate.

即:如果只关心最终状态,建议使用防抖。如果是想要函数以可控的速率执行,那么建议使用节流。

延时多久合理:

  • 大多数屏幕的刷新频率是每秒60Hz,浏览器的渲染页面的标准帧率也为60FPS,浏览器每秒会重绘60次,而每帧之间的时间间隔是DOM视图更新的最小间隔。
  • 一个平滑而流畅的动画,最佳的循环间隔即帧与帧的切换时间希望是 16.6ms(1s/60)内,也意味着17ms内的多次DOM改动会被合并为一次渲染。
  • 当执行回调函数时间大于16.6ms(系统屏幕限制的刷新频率),UI将会出现丢帧(即UI这一刻不会被渲染),且丢帧越多,引起卡顿情况更严重。

到此这篇关于JavaScript 防抖debounce与节流thorttle的文章就介绍到这了,更多相关JavaScript 防抖与节流内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!

您可能感兴趣的文章:
  • javascript函数的节流[throttle]与防抖[debounce]
  • javascript防抖函数debounce详解
  • Javascript节流函数throttle和防抖函数debounce
  • 关于JavaScript防抖与节流的区别与实现
  • 什么是JavaScript的防抖与节流
  • 详细聊一聊js防抖节流到底是什么

今天关于vue 节流throttling防抖debouncevue节流和防抖的分享就到这里,希望大家有所收获,若想了解更多关于debounce(防抖)和throttle(节流)、DebounceVsThrottle(防抖和节流)、JavaScript 函数节流 throttle 和防抖 debounce、JavaScript 防抖debounce与节流thorttle等相关知识,可以在本站进行查询。

本文标签: