防抖节流插件throttle-debounce

前言

最近一直在针对 Element-Ui 的源码进行学习,当然重点是学习人家的插件化思想和书写的逻辑性,还有精简(装~)的写法。

发现在源码中使用了 throttle-debounce 这个插件,特意查了一下用法,同时简单分析一下源码。

概念:

节流(Throttle):当事件被连续触发多次时,只有第一次触发会立即执行,后续的触发会根据设定的时间间隔进行限制。

防抖(Debounce):当事件被连续触发多次时,只有最后一次触发会生效,前面的触发将被取消。

使用

直接进行安装:

npm i throttle-debounce --save-dev

throttle方法

含义:固定时间执行回调方法。出现连续调用的函数时,按照特定频率调用函数。

debounce方法

含义:只调用一次回调方法。出现连续调用函数时,最后一次点击结束后,等待特定时间,调用一次函数。

<template>
    <div>
        <el-button type="primary" @click="debounceClick">debounceClick</el-button>
        <el-button type="primary" @click="throttleClick">throttleClick</el-button>
    </div>
</template>

<script>
import { debounce, throttle } from "throttle-debounce";

export default {
    name: 'SelectPage',
    data() {
        return {
            debounceCount: 0,
            throttleCount: 0,
        }
    },
    created() {
        this.refech1 = debounce(1000, () => {
            this.axiosApi();
        });
        this.refech2 = throttle(1000, () => {
            this.axiosApi();
        });
    },
    methods: {
        debounceClick() {
            this.debounceCount++;
            console.log('鼠标点击debounce', this.debounceCount);
            this.refech1();
        },

        throttleClick() {
            this.throttleCount++;
            console.log('鼠标点击throttle', this.throttleCount);
            this.refech2();
        },

        axiosApi() {
            console.log('触发接口');
        },
    }
}
</script>

原理

throttle 源码

/**
 * 限制函数的执行。特别适用于速率限制
 * 处理程序对事件(如调整大小和滚动)的执行。
 *
 * @param {number} delay - 以毫秒为单位,使用零或更大的数值。对于事件回调,推荐值为100或250(甚至更高)。
 * @param {Function} callback - 延迟毫秒后的回调函数。通过this将所有的参数原样执行回调函数。
 * @param {object} [options] - 可选配置。
 * @param {boolean} [options.noTrailing] - 可选, 默认为false。如果noTrailing为true,则回调函数将仅每隔“延迟”毫秒执行一次。如果noTrailing为false,或者不指定,则在最后一次调用后的某个时间节点会执行一次回调函数。也就是说即使不存在新的调用,回调函数仍然会被调用一次。(内部计数器每次都会重置,确保每次调用节流方法都是新的)。
 * @param {boolean} [options.noLeading] - 可选, 默认为false。如果noLeading为false,则第一次调用节流函数时,回调函数将被立即执行。如果noLeading为true则不会立即执行,也就是跳过第一次执行回调函数。
 * 如果noTrailing和noLeading都为 true,则永远不执行回调函数。
 * @param {boolean} [options.debounceMode] - 如果debounceMode为true,则清除内部计时器方法在节流函数开启“延迟”毫秒后执行。如果debounceMode为false,则清除内部计时器的方法在结束节流方法后“延迟”毫秒后执行。 

 * @returns {Function} 返回一个新的、已节流的函数。
 */
export default function (delay, callback, options) {
	// 通过解构获取配置参数
	const {
		noTrailing = false,
		noLeading = false,
		debounceMode = undefined
	} = options || {};
	/*
	 * 在停止调用包装器后,此超时确保在“throttle”和“end”反跳模式下的适当时间执行“callback”。
	 */
	let timeoutID;  // 延迟执行方法记录id
	let cancelled = false;

	// 记录上次执行“回调”的时间。
	let lastExec = 0;

	// 清除现有超时的功能
	// 实际为清除计时器
	function clearExistingTimeout() {
		if (timeoutID) {
			clearTimeout(timeoutID);
		}
	}

	// 用于取消下一次执行的函数
	function cancel(options) {
		const { upcomingOnly = false } = options || {};
		clearExistingTimeout();
		cancelled = !upcomingOnly;
	}

	/*
	 * “包装器”函数封装了所有的节流/去抖动功能,当执行时将限制“回调”的执行速率。
	 */
	function wrapper(...arguments_) {
		let self = this;
		let elapsed = Date.now() - lastExec;

		if (cancelled) {
			return;
		}

		// 执行“callback”并更新“lastExec”时间戳。
		function exec() {
			lastExec = Date.now();
			callback.apply(self, arguments_);
		}

		/*
		 * 如果“debounceMode”为true(在开始时),则用于清除标志以允许将来执行“回调”。
		 */
		function clear() {
			timeoutID = undefined;
		}

		if (!noLeading && debounceMode && !timeoutID) {
			/*
			 * 由于“wrapper”是第一次调用,并且“debounceMode”(在开始时)为true,因此执行 callback 和 noLeading != true。
			 */
			exec();
		}

		clearExistingTimeout();

		if (debounceMode === undefined && elapsed > delay) {
			if (noLeading) {
				/*
				 * 在noLeading的节流模式下,如果超过了“延迟”时间,请更新“lastExec”并计划“callback”在“延迟”ms后执行。
				 */
				lastExec = Date.now();
				if (!noTrailing) {
					timeoutID = setTimeout(debounceMode ? clear : exec, delay);
				}
			} else {
				/*
				 * 没有noLeading的节流模式下,如果超过了“延迟”时间,则立即执行 callback
				 */
				exec();
			}
		} else if (noTrailing !== true) {
			/*
			 * 在noTrailing为false的节流方法中,由于没有超过“延迟”时间,请安排“回调”在最近一次执行后执行“延迟”ms。
			 *
			 * 如果“debounceMode”为true(在开始时),则安排“clear”在“delay”ms之后执行。
			 *
			 * 如果“debounceMode”为false(在结束时),则安排“callback”在“delay”ms之后执行。
			 */
			timeoutID = setTimeout(
				debounceMode ? clear : exec,
				debounceMode === undefined ? delay - elapsed : delay
			);
		}
	}

	wrapper.cancel = cancel;

	// 返回包装器函数
	return wrapper;
}

debounce源码

export default function (delay, callback, options) {
	const { atBegin = false } = options || {};
	return throttle(delay, callback, { debounceMode: atBegin !== false });
}

相关推荐

  1. 节流throttle-debounce

    2024-03-21 17:54:04       46 阅读
  2. Debounce)和节流Throttle

    2024-03-21 17:54:04       41 阅读
  3. vue中使用lodash的debounce函数

    2024-03-21 17:54:04       60 阅读
  4. uniapp中函数debounce的使用

    2024-03-21 17:54:04       32 阅读
  5. 函数,节流函数

    2024-03-21 17:54:04       66 阅读
  6. lodash库(节流

    2024-03-21 17:54:04       36 阅读
  7. 精简版节流实现

    2024-03-21 17:54:04       44 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-21 17:54:04       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-21 17:54:04       100 阅读
  3. 在Django里面运行非项目文件

    2024-03-21 17:54:04       82 阅读
  4. Python语言-面向对象

    2024-03-21 17:54:04       91 阅读

热门阅读

  1. C++面试100问(十一)

    2024-03-21 17:54:04       40 阅读
  2. 【蓝桥杯】链式前向星

    2024-03-21 17:54:04       48 阅读
  3. python列表的创建、访问、切片和方法

    2024-03-21 17:54:04       47 阅读
  4. MySQL 管理用户授权 DCL

    2024-03-21 17:54:04       44 阅读
  5. PyTorch Dataset、DataLoader长度

    2024-03-21 17:54:04       43 阅读
  6. tornado上传文件

    2024-03-21 17:54:04       41 阅读
  7. 快速幂(技巧版)+ 一点点数学推理

    2024-03-21 17:54:04       41 阅读
  8. QRandomGenerator生成随机数

    2024-03-21 17:54:04       40 阅读
  9. ubuntu Docker无法使用zip unzip指令 解决方案 服务器

    2024-03-21 17:54:04       50 阅读
  10. 数据按设定单位(分辨率)划分的方法

    2024-03-21 17:54:04       43 阅读