skip to Main Content

I have a function that I call from a from a timeout that makes an ajax call. I also have a button click call that I don’t want to execute until the ajax call completes, if the ajax call is running. If the ajax call is not running, I want to run the button click code.

What is the best way to handle this? With a variable that you check to see if the ajax function is running or is there another way?

Here is my pseudo code

setTimeout(doAjax, 5000);

function doAjax() {
  $.ajax({
        url: "xxx.com/dosomething",
        dataType: 'json',
        type: 'POST',
        cache: false,
        contentType: 'application/json; charset=utf-8',
        success: function (data) { doSuccess() },
        error: function (data, status, jqXHR) { doError() }
    });
}

function myBtnClick() {
  // wait for doAjax call to complete if running
}

2

Answers


  1. The solution here is to use promises to maintain the state of your async code.

    let clickDelayPromise = Promise.resolve(); // initial value
    
    async function myBtnClick() {
      // wait for the promise to resolve
      await clickDelayPromise;
    
      // now do stuff
    }
    
    function doAjax() {
      // assign the $.ajax deferred (promise) to the variable
      clickDelayPromise = $.ajax({
        // ...
      });
    }
    

    Initially, the clickDelayPromise will resolve immediately but once the AJAX call begins, the promise will only resolve once the request completes.

    // mocks
    const $ = {ajax:()=>(console.log("ajax starting"),new Promise(r=>setTimeout(()=>{console.log("ajax done");r();},4000)))};
    
    let clickDelayPromise = Promise.resolve(); // initial value
    
    async function myBtnClick() {
      // wait for the promise to resolve
      await clickDelayPromise;
    
      // now do stuff
      console.log("button click!");
    }
    
    function doAjax() {
      // assign the $.ajax deferred (promise) to the variable
      clickDelayPromise = $.ajax({
        // ...
      });
    }
    
    setTimeout(doAjax, 5000);
    <button onclick="myBtnClick()">Click me lots</button>
    Login or Signup to reply.
  2. You can achieve what you want by making sure that your prerequisite async operations you have are promises and, if you have an array where you store them, then you can do something like this:

    Promise.all(yourArray).then((values) => {
        /*Do something*/
    })
    

    Proof-of-concept:

    function decreaseCounter() {
        let context = document.getElementById("counter");
        let value = parseInt(context.innerText);
        context.innerText = value - 1;
    }
    function test() {
        Promise.all(myPromises).then(() => {
            alert("Job Complete!");
        });
    }
    let myPromises = [
        new Promise(resolve => setTimeout(resolve, 1000)).then(decreaseCounter),
        new Promise(resolve => setTimeout(resolve, 2000)).then(decreaseCounter),
        new Promise(resolve => setTimeout(resolve, 3000)).then(decreaseCounter),
        new Promise(resolve => setTimeout(resolve, 4000)).then(decreaseCounter),
        new Promise(resolve => setTimeout(resolve, 5000)).then(decreaseCounter),
        new Promise(resolve => setTimeout(resolve, 6000)).then(decreaseCounter),
        new Promise(resolve => setTimeout(resolve, 7000)).then(decreaseCounter),
        new Promise(resolve => setTimeout(resolve, 8000)).then(decreaseCounter),
        new Promise(resolve => setTimeout(resolve, 9000)).then(decreaseCounter),
        new Promise(resolve => setTimeout(resolve, 10000)).then(decreaseCounter)
    ]
    This is the final countdown:
    <h1 id="counter">10</h1>
    
    <b>Click on the button to see whether it waits for the countdown</b><br>
    <input type="button" onclick="test()" value="Click Me">
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search