在现代前端开发中,防止用户快速重复点击按钮或执行某些操作是一个常见的需求。例如,用户在短时间内连续点击按钮时,我们可能只想执行第一次点击的操作,而忽略后续的重复点击。

为了解决这个问题,我们可以使用一个 锁定机制 来防止函数的多次调用。本文将介绍如何使用 Vue 3 中的 ref 和 async 函数来实现一个 useLockFn 自定义 Hook,它可以防止在短时间内重复执行一个异步操作。

需求分析

有些操作可能会被频繁触发,比如:
• 用户多次点击按钮发起网络请求。
• 连续调用同一个函数导致重复操作(例如,表单提交、数据保存等)。

为了避免这种重复操作,我们需要引入 锁机制,确保同一时刻只执行一次函数。

useLockFn 的实现

useLockFn 是一个高阶函数,它接受一个异步函数 fn 和一个可选的延迟 delay(默认为 600 毫秒)。它返回一个新函数,该函数会:
• 防止在指定的延迟时间内重复调用。
• 在异步操作完成前,锁住该函数,避免重复执行。

import { ref } from 'vue';

type ArgsAny = any[];

type Fn = (...args: ArgsAny) => Promise<any>;

export const useLockFn = (fn: Fn, delay = 600) => {
    const lock = ref(false);
    const lastDate = ref();

    return async (...args: ArgsAny) => {
        if (lock.value) return;
        const nowDate = new Date();

        if (lastDate?.value && nowDate.getTime() - lastDate?.value.getTime() <= delay) {
            return;
        }
        lastDate.value = nowDate;

        lock.value = true;
        try {
            const ret = await fn(...args);
            lock.value = false;
            return ret;
        } catch (error) {
            lock.value = false;
            throw error;
        }
    };
};