使 onClick 函数等待上一个调用结束
Make an onClick function wait the previous call to end
我正在使用 React,我在连续同步点击时遇到问题(onClick 事件):
我的按钮触发了一个调用两个函数resetViews
和chargeViews
的函数(chargeViews
需要时间),所以当我快速点击两次时:
resetView
执行得很好(它将 viewsRef.current
设置为 null)
- 然后
chargeViews
被调用,但由于它需要时间,因此不会立即更新 viewsRef.current
。
- 所以
resetView
被调用但是 viewsRef.current
仍然是空的(因为 chargeViews
还没有更新它)所以它什么都不做,
- 然后我得到两次延迟执行
chargeViews
- 所以在点击两次后我执行了 1 次
resetView
和两次延迟执行 chargeViews
我想要的是在点击后阻止所有内容(即使用户点击我们什么都不做)并执行 resetView
然后 chargeViews
然后取消阻止以接收另一个点击并做同样的工作。
<MyButton onClick={() => {
resetViews();
chargeViews();
}}>
Click me
</MyButton>
耗时函数
const chargeViews = () => {
if(!viewsRef.current){
...
reader.setUrl(url).then(()=>{
reader.loadData().then(()=>{
...
viewsRef.current = reader.getData();
})})
}}
点击太快就被忽略的功能,(点击没问题,稍等一下再点击)但是如果点击再快速点击就被忽略了。
const resetViews = () => {
if (viewsRef.current){
...
viewsRef.current = null;
}}
我不确定是否掌握了整个问题...如果不需要这么长的文本,这将是一条评论。
无论如何,只要您需要在单击按钮后禁用它,您应该在其 onclick 处理程序的开头处理它:
$(this.event.target).prop('disabled', true);
并在最后重置它:
$(this.event.target).prop('disabled', false);
总的来说,就调用要在处理程序内链式执行的多个函数而言,您所做的是正确的。但是这两个函数似乎有一个 promise 调用。在那种情况下,它们不会在链中执行,等待第一个函数完成。
因此您应该将第二次调用作为回调传递给第一次调用,以便只有在第一次调用完成其工作后才有机会调用它。
我希望有人会直截了当地建议如何使异步函数“等待”,以便无论它做什么,在调用时都会等待它完成,然后再评估下一个语句。通常这只是在其签名前添加 await
的问题,但有一些注意事项。
首先,您需要将 Promise-utilizing 函数转换为异步函数,然后在调用它们时等待它们。
这样可以更容易控制执行顺序:
const chargeViews = async () => {
if(!viewsRef.current){
...
await reader.setUrl(url);
await reader.loadData();
...
viewsRef.current = reader.getData();
}
}
然后,您需要一个 isExecuting 引用,它在其他调用正在执行时为真,在 none 当前正在执行时为假:
const isExecuting = useRef(false);
const handleClick = async () => {
if (!isExecuting.current) {
// block other clicks from performing actions in parallel
isExecuting.current = true;
try {
resetViews();
await chargeViews();
} finally {
// unblock other clicks
isExecuting.current = false;
}
}
};
最后,在您的 JSX 中使用 newly-created handleClick
函数:
<MyButton onClick={handleClick}>
Click me
</MyButton>
我正在使用 React,我在连续同步点击时遇到问题(onClick 事件):
我的按钮触发了一个调用两个函数resetViews
和chargeViews
的函数(chargeViews
需要时间),所以当我快速点击两次时:
resetView
执行得很好(它将viewsRef.current
设置为 null)- 然后
chargeViews
被调用,但由于它需要时间,因此不会立即更新viewsRef.current
。 - 所以
resetView
被调用但是viewsRef.current
仍然是空的(因为chargeViews
还没有更新它)所以它什么都不做, - 然后我得到两次延迟执行
chargeViews
- 所以在点击两次后我执行了 1 次
resetView
和两次延迟执行chargeViews
我想要的是在点击后阻止所有内容(即使用户点击我们什么都不做)并执行 resetView
然后 chargeViews
然后取消阻止以接收另一个点击并做同样的工作。
<MyButton onClick={() => {
resetViews();
chargeViews();
}}>
Click me
</MyButton>
耗时函数
const chargeViews = () => {
if(!viewsRef.current){
...
reader.setUrl(url).then(()=>{
reader.loadData().then(()=>{
...
viewsRef.current = reader.getData();
})})
}}
点击太快就被忽略的功能,(点击没问题,稍等一下再点击)但是如果点击再快速点击就被忽略了。
const resetViews = () => {
if (viewsRef.current){
...
viewsRef.current = null;
}}
我不确定是否掌握了整个问题...如果不需要这么长的文本,这将是一条评论。
无论如何,只要您需要在单击按钮后禁用它,您应该在其 onclick 处理程序的开头处理它:
$(this.event.target).prop('disabled', true);
并在最后重置它:
$(this.event.target).prop('disabled', false);
总的来说,就调用要在处理程序内链式执行的多个函数而言,您所做的是正确的。但是这两个函数似乎有一个 promise 调用。在那种情况下,它们不会在链中执行,等待第一个函数完成。
因此您应该将第二次调用作为回调传递给第一次调用,以便只有在第一次调用完成其工作后才有机会调用它。
我希望有人会直截了当地建议如何使异步函数“等待”,以便无论它做什么,在调用时都会等待它完成,然后再评估下一个语句。通常这只是在其签名前添加 await
的问题,但有一些注意事项。
首先,您需要将 Promise-utilizing 函数转换为异步函数,然后在调用它们时等待它们。 这样可以更容易控制执行顺序:
const chargeViews = async () => {
if(!viewsRef.current){
...
await reader.setUrl(url);
await reader.loadData();
...
viewsRef.current = reader.getData();
}
}
然后,您需要一个 isExecuting 引用,它在其他调用正在执行时为真,在 none 当前正在执行时为假:
const isExecuting = useRef(false);
const handleClick = async () => {
if (!isExecuting.current) {
// block other clicks from performing actions in parallel
isExecuting.current = true;
try {
resetViews();
await chargeViews();
} finally {
// unblock other clicks
isExecuting.current = false;
}
}
};
最后,在您的 JSX 中使用 newly-created handleClick
函数:
<MyButton onClick={handleClick}>
Click me
</MyButton>