CrazySynthax
CrazySynthax

Reputation: 15058

How to make asynchronous event handlers work in a certain order?

Let's say I have a button with an event handler:

<button onclick="btnClicked()"> CLICK ME </button>

and this is the js file:

var num = 0; // global variable

function btnClicked() { 
   num++;
   console.log(num);
}

Let's say that I clicked twice on the same button. I expect to see in console 1 and then 2.

But, it's not necessary that this is what I will get. Each button click invokes the function btnClicked asynchronously, so there is a possible scenario that the second call will end before the first call ends. e.g. The first invocation calls btnClicked, passes the line num++ and then holds (for some reason). Meanwhile, second invocation enters the function that num = 1, increments it to 2, prints 2 in console, and then the first invocation continues its execution with num=2 and therefore also prints 2.

Do you know any way to make sure that second invocation will occur only after first invocation ends ?

Upvotes: 2

Views: 898

Answers (4)

CrazySynthax
CrazySynthax

Reputation: 15058

After reading the responses I understood that the scenario that I describes (console will print "2" twice) is not possible.

Event handlers are added to event queue. Event Queues are not V8 threads. Therefore, each task in event queue will execute synchronously, i.e. only after the first invocation ends the second one will start.

However, if the function were:

function btnClicked() { 
   num++;
   console.log(num);
   **AJAX call** 
}

then the execution order would be: print: 1 AJAX call sent for first invocation print 2 AJAX call sent for second invocation

and then in this case both AJAX calls take place in different threads and we cannot know for sure which one of them will ends first.

Upvotes: 1

Alex Nikulin
Alex Nikulin

Reputation: 8689

You just need a promise for solving the order issue. Events are going each by each. But if you have an ajax request, and you need to send ajax requests each by each after you got a response from a server. And you send ajax request by a button click (asynchronous execution of functions by certain order, each by each). So here is a working example with fake execution function.

var num = 0;

var executing = new Promise(function(resolve, reject){
     resolve();
});

var btnHandle = function(){
  executing.then(createJobInstanse());
}

var createJobInstanse = function(){
 return function(){
      return new Promise(function(resolve, reject){
        // fake asynchronous operation from 10ms to 2000ms, with random execution time
        window.setTimeout(function(){
          console.log(num++);
          resolve();
        }, Math.floor(Math.random() * 2000) + 10);
      });
 };
}

  

var btn = document.querySelector("#btn");
btn.addEventListener("click",btnHandle);
<button id="btn" onclick="btnHandle">click</button>

Upvotes: 0

Frish
Frish

Reputation: 1421

While it may not address your problem directly, it is recommended to use eventListener instead of onclick.

Also, to make a variable global you would call it without 'var' -- perhaps not exactly something you'd want to do with something generic like 'num', but that would make it global (more on that here).

This would give you something like:

<button id='click-me'> CLICK ME </button>

<script>
    num = 0; // global variable
    document.getElementById('click-me').addEventListener('click', function(){
        // function here
    });
</script>

Upvotes: 0

user2446768
user2446768

Reputation: 11

On the button click, just disable the button and at end of the function enable the button. Can you try this. I think it will work for you.

Upvotes: 0

Related Questions