4 ms·
Debouncing exists for a reason. Sometimes when a button is clicked twice, you want it executed twice, sometimes you don't. Distinguishing which is better in whi
by mcv 3mo ago
Debouncing exists for a reason. Sometimes when a button is clicked twice, you want it executed twice, sometimes you don't. Distinguishing which is better in which situation is not trivial.
At the very least, you should consider which is appropriate for which situation, what if, in your UI, for some buttons one is the obvious choice, for others it's the other, but for some it's not so clear, and both behaviours are defensible? Now you've got an inconsistent UI.
I have no good solution for this.
- Timwi 3mo agoIt seems somewhat clear to me. You want it executed twice if and only if the operation isn't idempotent. Can you give an example where you think both behaviors are equally defensible?
- deleted 3mo ago[deleted]
- RossBencina 3mo agoI guess the downvotes signal disagreement, but I value the conversation in spite of disagreeing with you. I'm not sure idempotence is the only concept in play. If the operation is idempotent, well, clicking twice doesn't do anything. I'd still want to see the button light up to signal that the UI is alive, or the button could grey out or enter a "latched" state like a radio button if there is nothing to be done. Behind the scenes suppressing command propagation is an implementation detail and the trade off is between front-end complexity and redundant command execution overhead. If the operation is not idempotent I can give you separate examples where different behaviors are appropriate: 1. A button used to increment a counter (e.g. quantity of GPUs to buy) should increment on every click, even if the UI response is delayed. The user can count clicks, and there is going to be a decrement button to reverse any error. You do not want the user waiting around guessing whether the software is still processing the remaining clicks. As a rule, so long as the operation is non-destructive (e.g. inc and dec buttons, all operations reversible/undoable, etc.) every user interaction can and should be actioned. 2. A button used to perform an irreversible action, i.e. a "commit", such as placing the order to purchase a GPU, should only perform that operation once. I would not call this an idempotent operation, certainly not with respect to your bank balance.
- Timwi 3mo agoThe button to place an order should 100% be idempotent. There's one order you're constructing in your shopping cart, perhaps with an internal ID, and the irreversible “commit” button should place that order, not create two separate orders.
- kccqzy 3mo agoIt’s really common for people to accidentally click a button twice. Yeah that’s what denouncing is for. My favorite example of doing it wrong is a log in form: if the login button is clicked twice, the server would reject the login because the first click has already used up the one-time token so the user gets an error page. But I think the biggest problem is that people either apply denouncing to all buttons in a UI (like turning it on within the framework they are using) or apply denouncing to nothing. So there really isn’t a culture for carefully considering which situations warrant which.
- earth-tattoo 3mo ago[flagged]
- PunchyHamster 3mo agothe correct action is not to debounce but instead of error page see user already logged in in previous request and continue
- jonahx 3mo agoI think the better solution for a web page login form specifically is to disable the button "onPressDown", so this error path is impossible. For users with JS disabled, your solution seems good.
- stavros 3mo agoThe correct action is to disable the button while the request is in flight so it can't be clicked a second time. Otherwise you won't see "user already logged in", because the user won't be logged in until the previous request returns (a race condition).
- LordDragonfang 3mo agoIf you have a race condition, "correct action" is to solve that, because you shouldn't be papering over server-side bugs with client-side Javascript (and yes, it's a bug, because I shouldn't see an error page if I press the back button after logging in (and trying to navigate to what I was doing before logging in) either, which I still see quite often)
- efficax 3mo agoa button that debounces requests should be disabled until the action is complete instead, so you can only click it once until it is ready to be clicked again. debouncing button clicks is a design failure (it makes more sense for things like requests that happen during typing, where you don't want to stop the feedback)
- Someone 3mo agoThere always will be time between the first click and the time the button gets disabled and even more time before the visual representation of the button gets updated to reflect that. Keeping that time so short that it is impossible for a human to click the button again can be very hard. It would help if GUI elements had a property “automatically disable on click”, removing the need for the “on click handler” to disable the button (in exchange for adding the need to explicitly re-enable it). I don’t remember seeing GUI libraries that do that, though. That probably is because it would confuse users if buttons visually get disabled when they click them. So, the best answer is to visually keep the button enabled, but ignore rapid further clicks. That’s debouncing.
- QuercusMax 3mo agoThis is a fundamental misunderstanding of how GUIs must necessarily work. There should be no possibility of race conditions if you understand the threading model. The visual representation updating (greying out button) is a result of disabling the button, not the same thing. In virtually every GUI toolkit I've ever used there is the concept of the main UI thread, and everything that happens (input and display updates) necessarily has to go through that single thread in order to ensure correctness. (This applies to browsers, too.) That's why input goes into a queue, so you can easily do things like: (All on the main UI thread): - Receive click event 1: disable button, start background process. Possibly redraw button UI *but it doesn't matter because the UI display is not the state, it's just a view*. - Receive click event 2: nothing happens, button is disabled - Background process finishes, posts update to re-enable the button - Receive click event 3: disable button, start background process, etc.
- nullsanity 3mo ago
- account42 3mo agoDebouncing also has nothing to do with the animation shown on the screen so tying the debounce time to the animation is almost certainly wrong no matter what those tradeoffs are.