Reputation: 53
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
}
Upvotes: 2
Views: 448
Reputation: 76454
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">
Upvotes: 1
Reputation: 164767
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>
Upvotes: 1