防抖节流

  1. 防抖(debounce)

    先来看看下面的代码:

    //触发滚动事件,num 就加1
    let num = 0; function incNum() {
    console.log('鼠标滚动中');
    console.log(`${num++} ${Date().getSeconds()}s`);
    } window.addEventListener('scroll', incNum, false);

    当滚动鼠标,num会疯狂加1,从下图中可以看到稍微滚动一下鼠标就输出了N个num

    • 什么是防抖?

      防抖指的是让某些代码不可以在没有间断的情况下连续重复地执行。举个例子,一部电梯开门等待30s就会关门上升,在这30s的等待时间里,有人进来了,30s就重新从0开始计时,然后又有人进来了,30s就又重新计时,直到等待时间30s超时才会关门上升。

    • 实现防抖

      以上面的代码为例子来说明如何实现防抖:一直滚动鼠标,第一次触发scroll事件,在事件的执行函数里创建一个定时器,在指定的时间间隔后才运行相关代码。然后第二次触发scroll事件,如果此时前面设置的定时器还没开始执行,就清除前一次的定时器并重新设置一个。这么做的目的就是让scroll事件的执行函数在事件停止触发一段时间后才去执行,以此实现防抖。

      function debounce(func, delay) {
      let timeout; return function(){
      // context 是为了绑定 this
      let context = this;
      // args 是为了能正常使用事件对象 event
      let args = arguments; if (timeout) clearTimeout(timeout);
      timeout = setTimeout(()=> {
      func.apply(context, args);
      }, delay);
      }
      } window.addEventListener('scroll', debounce(incNum, 1000), false);

      从下面图片可以看出,防抖处理后,只有在鼠标停止滚动一段时间后,才会输出num和秒数。

    • 取消执行

      当滚动鼠标后,在1s的等待时间里,突然想取消运行 scroll事件的函数了,该怎么办呢?

      答案是:在定时器没运行前,清除定时器。

      function debounce(func, delay) {
      let timeout; let debounced = function(){
      let context = this;
      let args = arguments; if (timeout) clearTimeout(timeout);
      timeout = setTimeout(()=> {
      func.apply(context, args);
      }, delay);
      } // 取消将要执行的定时器
      debounced.cancel = function() {
      clearTimeout(timeout);
      timeout = null;
      console.log('已取消');
      } return debounced;
      } let testFunc = debounce(incNum, 1000);
      window.addEventListener('scroll', testFunc, false);
      // 在页面的按钮上绑定取消函数
      document.getElementById('cancel').addEventListener('click', testFunc.cancel, false);
    • 立即执行

      只要触发scroll事件,函数就立即执行,但必须要在函数执行完毕并过了一段时间后,再次滚动鼠标才会再次执行函数,而在等待时间里,如果滚动鼠标,等待时间会重新计时。

      function debounce(func, delay, immediate) {
      let timeout; let debounced = function(){
      let context = this;
      let args = arguments; if (timeout) clearTimeout(timeout);
      // immediate 为 true 就表示立即执行,忽略或者为 false 即非立即执行
      if (immediate) {
      let callNow = !timeout;
      timeout = setTimeout(()=> {
      timeout = null;
      }, delay);
      if (callNow) func.apply(context, args);
      } else {
      timeout = setTimeout(()=> {
      func.apply(context, args);
      }, delay);
      }
      } // 取消将要执行的定时器
      debounced.cancel = function() {
      clearTimeout(timeout);
      timeout = null;
      console.log('已取消');
      } return debounced;
      } window.addEventListener('scroll', debounce(incNum, 1000, true), false);
  2. 节流(throttle)

    • 什么是节流?

      还是电梯的例子:一部电梯开门等待30s就会关门上升,在这30s的等待时间里,有人进来了,计时继续累计,然后又有人进来了,计时依然累计,然后30s计时到了就立即关门上升(我还没上车呢.jpg)。

      简单来说,就是连续触发事件,但在固定时间内只执行一次函数。

    • 定时器实现

      // 定时器版本,鼠标滚动1s后才执行函数
      function throttle(func, delay){
      let timeout;
      return function(){
      let context = this;
      let args = arguments;
      if (!timeout) {
      timeout = setTimeout(()=> {
      func.apply(context, args);
      }, delay);
      }
      }
      } window.addEventListener('scroll', throttle(incNum, 1000), false);

      疯狂滚动鼠标,但从下图可以看出函数只每秒执行一次。

    • 时间戳实现

      // 时间戳版本,鼠标滚动函数立即执行,间隔1s再执行下一次
      function throttle(func, delay) {
      let previous = 0; return function() {
      let now = Date.now();
      let args = arguments;
      if ( (now - previous) >= delay ) {
      func.apply(this, args);
      previous = now;
      }
      }
      } window.addEventListener('scroll', throttle(incNum, 1000), false);
    • 合并实现与取消

      将定时器和时间戳两个版本合并在一起,可以实现滚动鼠标,函数就立即执行,间隔1s再执行下一次,然后停止滚动鼠标后,还会多执行一次的效果。

      function throttle(func, delay) {
      let previous = 0;
      let timeout;
      let now; let throttled = function() {
      now = Date.now();
      let context = this;
      let args = arguments;
      if ( (now - previous) >= delay ) {
      if (timeout) {
      clearTimeout(timeout);
      timeout = null;
      }
      previous = now;
      func.apply(context, args);
      } else if (!timeout) {
      timeout = setTimeout(()=> {
      previous = now;
      timeout = null;
      func.apply(context, args);
      }, delay - (now - previous));
      }
      } // 取消函数
      throttled.cancel = function() {
      clearTimeout(timeout);
      previous = 0;
      timeout = null;
      } return throttled;
      } let testFunc = throttle(incNum, 1000);
      window.addEventListener('scroll', testFunc, false);
      // 在页面的按钮上绑定取消函数
      document.getElementById('cancel').addEventListener('click', testFunc.cancel, false);

JS: 防抖节流的更多相关文章

  1. js 防抖 节流 JavaScript

    实际工作中,通过监听某些事件,如scroll事件检测滚动位置,根据滚动位置显示返回顶部按钮:如resize事件,对某些自适应页面调整DOM的渲染:如keyup事件,监听文字输入并调用接口进行模糊匹配等 ...

  2. js 防抖 节流

    函数防抖:将几次操作合并为一此操作进行.原理是维护一个计时器,规定在delay时间后触发函数,但是在delay时间内再次触发的话,就会取消之前的计时器而重新设置.这样一来,只有最后一次操作能被触发.( ...

  3. js防抖节流

    防抖(debounce) 所谓防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间. 防抖函数分为非立即执行版和立即执行版. 非立即执行版: 第一 ...

  4. 深入理解JS防抖与节流

    参考博客:JS防抖和节流,感谢作者的用心分享 日常开发过程中,滚动事件做复杂计算频繁调用回调函数很可能会造成页面的卡顿,这时候我们更希望把多次计算合并成一次,只操作一个精确点,JS把这种方式称为deb ...

  5. js 函数节流和防抖

    js 函数节流和防抖 throttle 节流 事件触发到结束后只执行一次. 应用场景 触发mousemove事件的时候, 如鼠标移动. 触发keyup事件的情况, 如搜索. 触发scroll事件的时候 ...

  6. js防抖和节流优化浏览器滚动条滚动到最下面时加载更多数据

    防抖和节流,主要是用来防止过于平凡的执行某个操作,如浏览器窗口变化执行某个操作,监听某个input输入框keyup变化,瀑布流布局时Y轴滚动,图片加载. js函数的防抖 经过一段事件才执行某个操作,如 ...

  7. 因为它,我差点删库跑路:js防抖与节流

    前言 前端踩雷:短时间内重复提交导致数据重复. 对于前端大佬来说,防抖和节流的技术应用都是基本操作.对于"兼职"前端开发的来说,这些都是需要躺平的坑. 我们今天就来盘一盘js防抖与 ...

  8. 面试必问题:JS防抖与节流

    摘要:防抖与节流可谓是面试常见,其实很好理解,下面带你分分钟了解防抖与节流的基本思想与写法~ 本文分享自华为云社区<JS防抖与节流快速了解与应用>,作者:北极光之夜. . 一.速识防抖: ...

  9. vue防抖节流之v-debounce--throttle使用指南

    最新封装了一个vue防抖节流自定义指令,发布到npm上,有用欢迎star,谢谢! npm地址:https://www.npmjs.com/package/v-debounce-throttle git ...

随机推荐

  1. 2018.10.14 loj#6011. 「网络流 24 题」运输问题(费用流)

    传送门 费用流入门题. 直接按照题意模拟. 把货物的数量当做容量建边. 然后跑一次最小费用流和最大费用流就行了. 代码: #include<bits/stdc++.h> #define N ...

  2. 2018.06.29 NOIP模拟 排列(线段树)

    排列(premu.cpp) [题目描述] 对于一个 1 到 n 的排列,逆序数的定义为:排列中第 i 位 ai的逆序数就是 a1-ai-1中比 ai大的数的个数.另外用 pi表示 a1,-,ai的逆序 ...

  3. 2018.07.12 atcoder Go Home(贪心)

    传送门 题意简述:大家在数轴上生活,公司在 s. 班车送所有人回家,有 n 个住处,第 i 个位置在 xi,居住了 pi 的人. 保证 xi 互不相同. 大家⼀起投票向前还是向后,如果票数相同就固定向 ...

  4. T4系列文章之2:T4工具简介、调试以及T4运行原理(转)

    出处:http://www.cnblogs.com/damonlan/archive/2012/01/12/2320429.html 一.前言 经过第一篇,我想大家现在对T4有了基本的印象,应该对T4 ...

  5. 第1章 (名词)Le nom

    ★名词的种类:(1)普通名词 —专有名词,如:          un livre —la Chine(2)可数名词—不可数名词,如:          un ami —le lait(3)具体名词— ...

  6. C++之类和对象的使用(三)

    对象数组 如果构造函数只有一个参数,在定义数组时可以直接在等号后面的花括号内提供.Student stud[3]={90,92,01};//合法 如果构造函数有多个参数,则不能用在定义时直接所提供所有 ...

  7. IntelliJ IDEA 2017版 spring-boot与Mybatis简单整合

    一.编译器建立项目 参考:http://www.cnblogs.com/liuyangfirst/p/8372291.html 二.代码编辑 1.建立数据库 /* Navicat MySQL Data ...

  8. UVaLive 3645 Objective: Berlin (最大流)

    题意:有n个城市,m条航班.已知每条航班的起点和终点,还有每条航班的载客量.出发时间.到达时间.并且要求在任何一个城市(起点.终点除外)都至少要有30分钟的中转时间,求起点到终点的最大客流量. 析:把 ...

  9. [可用]android hack

    msfvenom -p android/meterpreter/reverse_tcp LHOST=192.168.1.237 LPORT=4444 R > shell.apk service ...

  10. SPSS-多重响应-频率和交叉表案例分析(问卷调查分析)

    在10.1休假前,希望跟大家讨论一下SPSS-多重响应--频率和交叉表分析,希望大家能够多提点提点 在云南电信网上营业厅做了一个关于“客户不使用电信3g业务的原因有哪些的问卷调查,问题所示: 这份问卷 ...