12

I have a function which is executed on a click (or taphold) because I am working with Cordova.

The problem is that a function calls on the next object from Parse.com which shows its details but, for some reason, it executes the function twice or even 3 times, skipping 1 or 2 objects that have to be shown.

I want to prevent this from happening, so I already used a flag (boolean) to indicate if it was executed by setting it to true. If the flag was false, it can be executed and the flag is set to true. The other problem is that when I call the function one more time, the boolean is still set to true and the function will not be executed.

Therefore I cannot initialize the flag to false inside the method, because then it will always be executed. Global variable will be set to true the first time and stay true for the rest of it's "life".

I tried a second method by using a counter and making sure that if the counter reached, let's say 0, it could be executed, but then I have the same problem for setting it back to 0 when it reaches the end .. Let's say the function got executed twice, I could check if the counter reaches 2 (by incrementing it every time) and set it back to 0. Then when the next time it gets executed, it executes 3 times, so when the check happens if the counter reaches 2 .. it get's set back to 0 and the next execution (the 3rd one) will be executed again because the counter is 0 again.

How do I catch this or prevent this from happening?

I made a basic Javascript to show you what I mean:

window.addEventListener("load",setup,false);
var counter = 0;
function setup() {
   for(var i = 0; i < 3; i++) {
       showAlert();
   }
}

function showAlert() {
   if(counter == 0) {
       alert("Executed once");
       counter++;
   } else if(counter > 2) //counter is bigger than 2, so it got executed more than once {
       counter = 0; //reset the counter to 0
   }          
}

The goal is to prevent the function from executing more than once (in this case, the alert may not be shown more than once). It could be executed twice or even three times, or even more. How do I prevent this?

Thank you! I do know a bit about programming, but this is something I have never encountered so far, so I do not know how I can catch this and make sure it's executed once?

Mifeet
  • 12,949
  • 5
  • 60
  • 108
Jorrex
  • 1,503
  • 3
  • 13
  • 32
  • Are you looking for a function that can only be called every X seconds (such as lodash's [_.debounce](https://lodash.com/docs#debounce) helper) or a function that can only be called again after it has completed an operation? – Lexi Feb 19 '15 at 15:25
  • I'm looking for a function has to be called once when the user clicks on it, but for some reason Cordova executes it once, twice or even three times. So I'm looking for a way to prevent this from happening. – Jorrex Feb 19 '15 at 15:35

2 Answers2

27

You are experiencing "bounce", a problem caused by one impact registering multiple times in short succession. To get around it, you need to put a very short timeout on your function. (20ms or so) You can either use a third-party library such as LoDash which has many useful utility functions such as _.debounce which performs this, or you can do it yourself like this:

var lastClick = 0;
var delay = 20;

function doClick() {
  if (lastClick >= (Date.now() - delay))
    return;
  lastClick = Date.now();

  // do things
  alert("Hello!");
}
<button onclick="doClick()">Push me</button>
Lexi
  • 1,670
  • 1
  • 19
  • 35
  • So if I got this correct, I can use the "setTimeout" function too? from the moment it is executed, it holds for like a second and then gets executed? Or is this something entirely else? – Jorrex Feb 19 '15 at 17:59
  • I just tested this code and it isn't working :( it keeps skipping certain objects (so it keeps executing more than once) – Jorrex Feb 19 '15 at 18:34
  • @Jorrex You can try increasing the timeout period to 100ms. Alternatively, you could disable the button as soon as it is pressed and only re-enable it once it has finished fetching the data. That way it cannot ever skip items. – Lexi Feb 21 '15 at 08:59
  • 2
    Shouldn't it be `lastClick >= (Date.now() - 20)`? – raphael May 09 '16 at 15:00
4

This is a similar code but you should avoid these forced delays. Use this structure just for debugging.

const delay = 500; // anti-rebound for 500ms
let lastExecution = 0;

function myFunction(){
    if ((lastExecution + delay) < Date.now()){
       // execute my lines
       lastExecution = Date.now() 
    }
}
Banzy
  • 1,590
  • 15
  • 14