I have made a PHP script that sends an email to many users by looping through the users' ID via POST. When I try using the script with a lot of users (1000+), the script times out.
To resolve this, I decided to use AJAX on the front end that sends each request individually. I have set up a simple sample page to test my code. The PHP script delays for five seconds. I would expect to get a request per five seconds. However, I am getting a delay of five seconds, and then all of the responses at once. With more research, I discovered that my AJAX calls are chaining, which is not what I want. Rather, I would only like to send the next request when the last AJAX call was completed.
<form id='frmAjax' method='post' action='run_form.php'>
<span>1</span><input type="checkbox" name='option' value='test1'><br>
<span>2</span><input type="checkbox" name='option' value='test2'><br>
<span>3</span><input type="checkbox" name='option' value='test3'><br>
<span>4</span><input type="checkbox" name='option' value='test4'><br>
<span>5</span><input type="checkbox" name='option' value='test5'><br>
<span>6</span><input type="checkbox" name='option' value='test6'><br>
<span>7</span><input type="checkbox" name='option' value='test7'><br>
<span>8</span><input type="checkbox" name='option' value='test8'><br>
<span>9</span><input type="checkbox" name='option' value='test9'><br>
<input id='btnAjax' type='button' value='Submit AJAX'>
</form>
$("#btnAjax").click(function() {
var options = $("#frmAjax input:checkbox:checked");
$(options).each(function(i) {
var postData = {option: $(options[i]).val()};
$.ajax({
type: "POST",
data: postData,
url: "run_ajax.php",
success: function(result) {
console.log(result);
},
statusCode: {
500: function() {
console.log("Error");
}
}
});
});
});
<?
echo("Success on ".$_POST["option"].".");
sleep(5);
?>
My question is this, how can I make my AJAX calls recursive, not sending the next request until the previous has finished?
You can use your success
function and call the next ajax
request like something like this:
let optionsLength = 0;
let optionsCount = 0;
$("#btnAjax").click(function() {
optionsLength = $("#frmAjax input:checkbox:checked").length;
callAjax();
});
function callAjax() {
let postData = {option: $(options[optionsLength-optionsCount]).val()};
$.ajax({
type: "POST",
data: postData,
url: "run_ajax.php",
success: function(result) {
optionsCount = optionsCount + 1;
callAjax();
},
statusCode: {
500: function() {
console.log("Error");
}
}
});
}
this is somewhat pseudo code, you will probably have to tweak it but it should give you a good idea I hope..
Try with this one, you were not so far anyway ;)
function sendMail($options){
if (!$options.length) return;
$.ajax({
type: "POST",
url: "run_ajax.php",
data: {option:$options.eq(0).val()},
success: function(result){
console.log(result)
},
statusCode: {
500: function(){
console.log("Error")
}
}
}).always(function(){
sendMail($options.slice(1))
});
}
$("#btnAjax").on('click',function(e){
e.preventDefault();
sendMail($("#frmAjax input:checkbox:checked"));
});
Some points to help I hope :
For your PHP script timeout, you can venture into set_time_limit(0)
for endless script running.
For your responses that seems simultaneous. Your PHP is probably multi-threaded, so it will treat each request in parallel and, therefore, you'll receive each response 5s after each request have been sent. The solution is, as you're pointing, to delay each request sending.
For your case, simply create a queue but better use complete callback if you don't want the process to stop at the first error :
$("#btnAjax").click(function() {
function process(i) {
$.ajax({
type: "POST",
data: queue[i],
url: "run_ajax.php",
success: function(result) {
console.log(result);
},
statusCode: {
500: function() {
console.log("Error");
}
},
complete: {
if(i++ < (queue.length - 1) process(i);
}
});
}
var queue = [];
var options = $("#frmAjax input:checkbox:checked");
$(options).each(function(i) queue.push({option: $(options[i]).val()});
process(0);
});
This is what I mean by pass all your data about what is checked in one request. Pass the whole form. The overhead you introduce sending one value at a time makes no sense.
$("#btnAjax").click(function() {
var myform = document.getElementById("frmAjax");
var fd = new FormData(myform);
$.ajax({
type: "POST",
data: fd,
url: "run_ajax.php",
success: function(result) {
console.log(result);
},
statusCode: {
500: function() {
console.log("Error");
}
}
});
});
Your server side code then of course needs to handle iterating over the set of data.
If you need to know the individual outcomes of what transpires on the server then have your rux_ajax.php
script return JSON with that detail.