乐趣区

关于javascript:JS-如何实现上次操作未完成之前禁止新的操作的逻辑

置信很多人都遇到过相似的场景:
某一个按钮是用来发送申请的,并且须要一段时间来解决。然而用户往往会在解决期间无意或无心地点击屡次,因而咱们心愿在上一次收回的申请处理完毕之前,不再收回新的申请。

1. 初步解决计划:特事特办

“特事特办”的意思,就是每次遇到这样的场景,都特意写一段逻辑来解决:

document.addEventListener('click', (() => {
    let lock = false;
    return () => {if(lock) return;
        lock = true;
        console.log('clicked');
        // 为了不便测试就应用延时了
        setTimeout(() => {lock = false;}, Math.random() * 4e3)
    }
})());

2. 基于约定回调的条件式回调函数

下面的写法其实也不麻烦,然而这种条件限度能不能像曾经被面试问烂了的“节流 ”和“ 防抖 ”那样,用一个函数把它包裹起来就能够达成成果呢?
问题的要害其实在于:防抖和节流须要思考的执行条件是工夫,这个条件对于所有函数而言都是一个“独特的语言”,因而才单方能够做到那样的“默契”。
而要在这种场景里实现同样的成果,单方须要刻意的约定:例如被条件执行的函数额定承受一个函数,用于在适合的机会解除条件限度。

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

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

👆 为了不便形容这种约定对callback 的要求,这里应用 TS 而不是 JS

应用的时候:

button.addEventListener('click', conditioned((release) => {return () => {console.log('clicked');
        setTimeout(() => {release(); // 开释 lock
        }, Math.random() * 4e3);
    }
}));

3. 基于 Promise 的条件式回调函数

如果说有什么办法能比回调函数更“优雅”、更“通用”一些,答案显然是 Promise
因为下面的写法对原来的回调函数的参数进行了改写,遇到一个喜好 Ctrl + C 的初学者的话,他会纳闷复制过去的函数为什么就不工作了。

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

应用办法:

button.addEventListener('click', conditioned(() => {return new Promise((resolve) => {console.log('clicked');
      setTimeout(() => {resolve(); // 开释 lock
      }, Math.random() * 4e3);
  });
}));

尽管乍一看,应用这个函数意味着必须把回调函数的返回值改写成 Promise,不过因为这种场景往往都是异步操作,改成 async 何乐而不为呢?

4. React hook 版

import {useRef} from 'react';
function useCondition(callback: (...args: any[]) => Promise<any>) {const lock = useRef(false);

  return async (...args:any[]) => {if(lock.current) return;
    lock.current = true;
    try{await callback(...args);
      lock.current = false
    } catch(error){
      lock.current = false;
      throw error;
    }
  };
}

应用办法:

<button
  onClick={useCondition(() => {return new Promise<void>((resolve) => {console.log('clicked');
      setTimeout(() => {resolve(); // 开释 lock
      }, Math.random() * 4e3);
    });
  })}
> 测试 </button>

👆实际上没测试过,不晓得行不行的。

退出移动版