防抖和节流的应用场景和实现

防抖和节流的应用场景和实现

技术杂谈小彩虹2021-07-09 11:59:53110A+A-

防抖

防抖就是将一段时间内连续的多次触发转化为一次触发。

使用场景

一般可以使用在用户输入停止一段时间过后再去获取数据,而不是每次输入都去获取,如下图:

实现代码

  function debounce<Return>( fn: (...params: any[]) => Return, wait: number, /** 等待时间 */ immediate: boolean /** 是否立刻执行一次 */ ): Executor<Return> {
    const now: () => number = Date.now.bind(Date);
    let lastTime: number = 0;
    let timer: number = null;
    let params: IArguments = null;
    let _this: Function | null = null;

    function later(): void {
      const nowTime: number = now();

      if (nowTime - lastTime < wait) {
        // 如果还不够等待时间则继续等待
        const remainTime = wait - (nowTime - lastTime);

        timer = setTimeout(later, remainTime);
      } else {
        // 已到等待时间,执行回调
        debouncer.result = fn.apply(_this, params);

        timer = null;
        _this = null;
        params = null;
      }
    }

    function execute(): (Return | null) {
      lastTime = now();
      _this = this;
      params = arguments;

      try {
        if (immediate && timer === null) {
          // 立刻执行一次
          debouncer.result = fn.apply(_this, params);
        }

        return debouncer.result;
      } finally {
        if (timer === null) {
          // 加入时间队列,等待执行
          timer = setTimeout(later, wait);
        }
      }
    }

    // 创建执行器
    const debouncer: Executor<Return> = {
      execute,
      result: null,
    };

    return debouncer;
  };

原理很简单,主要是判断是否到达等待时间,如果没到达的话就继续加入任务队列等待执行。使用方法:

import utils from '../index';

const input = document.querySelector('input');
const executor = utils.fn.debounce(function(value) {
  console.log('fetch');
  
  return value;
}, 300);

let value = null;

input.addEventListener('input', function(e) {
  executor.execute(e.target.value);
  value = executor.result;
});

返回一个执行器的原因是这样可以方便获取最后一次函数执行时返回的值。

节流

节流顾名思义则是将减少一段时间内触发的频率。

使用场景

可以将一些事件降低触发频率。比如懒加载时要监听计算滚动条的位置,但不必每次滑动都触发,可以降低计算的频率,而不必去浪费资源;另外还有做商品预览图的放大镜效果时,不必每次鼠标移动都计算位置。

实现代码

throttle: function <Return>( fn: (...params: any[]) => Return, wait: number, {
      isExecuteAtStart = true,
      isExecuteAtEnd = true,
    }: ThrottleOptions = {
      isExecuteAtStart: true,
      isExecuteAtEnd: true,
    }
  ): Executor<Return> {
    let timer: number = null;
    let _this: Function = null;
    let params: IArguments = null;

    function execute(): (Return | null) {
      _this = this;
      params = arguments;

      if (isExecuteAtStart && timer === null) {
        // 如果需要开始的时候执行且没有计时器
        executor.result = fn.apply(_this, params);
        _this = null;
        params = null;
      }

      if (isExecuteAtEnd) {
        // 如果结束的时候需要执行
        if (timer === null) {
          timer = setTimeout(function () {
            executor.result = fn.apply(_this, params);
            _this = null;
            params = null;
            timer = null;
          }, wait);
        }
      }

      return executor.result;
    }

    const executor: Executor<Return> = {
      execute,
      result: null
    };

    return executor;
}

最后

防抖和节流的目的都是为了减少不必要的计算,不浪费资源,只在适合的时候再进行触发计算。源码可以在这个项目里的fn模块看到,另外还有许多实用的功能,欢迎使用和学习。如果我的文章对你有些帮助的话,可以点个赞,谢谢~

点击这里复制本文地址 以上内容由权冠洲的博客整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!

支持Ctrl+Enter提交

联系我们| 本站介绍| 留言建议 | 交换友链 | 域名展示
本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除

权冠洲的博客 © All Rights Reserved.  Copyright quanguanzhou.top All Rights Reserved
苏公网安备 32030302000848号   苏ICP备20033101号-1

联系我们