SoFunction
Updated on 2025-04-10

JS implements the logical special operation plan for "the last operation was not completed and prohibited new operations"

Scene

I believe many people have encountered similar scenarios:

A button is used to send a request and takes some time to process it. However, users often click on it intentionally or unintentionally multiple times during processing, so we hope that new requests will not be issued before the last request is processed.

1. Preliminary solution: special matters

The meaning of "special matters" is that every time you encounter such a scene, you will write a paragraph of logic to deal with it:

('click', (() => {
    let lock = false;
    return () => {
        if(lock) return;
        lock = true;
        ('clicked');
        // Use delay for easy testing        setTimeout(() => {
            lock = false;
        }, () * 4e3)
    }
})());

2. Conditional callback function based on convention callback

The above writing method is actually not a problem, but can this kind of conditional limit be like a bad interview question?Throttle"and"Anti-shake"In that way, can you achieve the effect by wrapping it with a function?
The key to the problem is actually: the execution condition that needs to be considered for anti-shake and throttling is time. This condition is a "common language" for all functions, so both parties can achieve such a "tactic understanding".
To achieve the same effect in this scenario, both parties need to deliberately agree: for example, the function executed by the condition accepts an additional function to be used to lift the conditional limit at the right time.

function conditioned(callback:(release:Function,...args:any[]) => any){
    let lock = false;
      return function(...args:any[]){
        if(lock) return;
        lock = true;
        (this, () => {
              lock = false;
        }, ...args);
      }
}

👆 To facilitate the description of this agreementcallbackRequirements, TS is used instead of JS.

When using:

('click', conditioned((release) => {
    return () => {
        ('clicked');
        setTimeout(() => {
            release(); // Release lock        }, () * 4e3);
    }
}));

3. Promise-based conditional callback function

If there is any method that can be more "elegant" and "general" than callback functions, the answer is obviouslyPromise

Because the above writing method rewritten the parameters of the original callback function, if you encounter a beginner who likes Ctrl + C, he will wonder why the copied function does not work.

function conditioned(callback:(...args:any[]) => Promise<any>){
    let lock = false;
    return function(...args:any[]){
        if(lock) return;
        lock = true;
        try {
            await (this, ...args);
            lock = false;
        } catch(err) {
            lock = false;
            throw err;
        }
    }
}

How to use:

('click', conditioned(() =&gt; {
  return new Promise((resolve) =&gt; {
      ('clicked');
      setTimeout(() =&gt; {
          resolve(); // Release lock      }, () * 4e3);
  });
}));

Although at first glance, using this function means that the return value of the callback function must be rewritten asPromise, but since this kind of scenarios are often asynchronous operations, it is changed toasyncWhy not do it?

4. React hook version

import { useRef } from 'react';
function useCondition(callback: (...args: any[]) => Promise<any>) {
  const lock = useRef(false);
  return async (...args:any[]) => {
    if() return;
     = true;
    try{
      await callback(...args);
       = false
    } catch(error){
       = false;
      throw error;
    }
  };
}

How to use:

&lt;button
  onClick={useCondition(() =&gt; {
    return new Promise&lt;void&gt;((resolve) =&gt; {
      ('clicked');
      setTimeout(() =&gt; {
          resolve(); // Release lock      }, () * 4e3);
    });
  })}
&gt;test&lt;/button&gt;

👆I haven't actually tested it, I don't know if it works. For more information about JS's ban on new operations last time, please pay attention to my other related articles!