Rate limiting with multiple ajax requests - javascript

I'm trying to ratelimit my ajax requests in order to remain within api limits. I make one request to my server which returns a list of data. From that list of data, I make a request to an api which does not allow receiving more than one request per second. How can I use setTimeout or a similar function to limit my requests?
myArray = ['1','2','3'];
function f1(){
for (var num in myArray){
$.ajax({
type: "POST",
url: "backend.php",
data: {suburbs : num},
success: function(data){
for (var item in data){
f2(data[item])
}
}
});
}
}
function f2(text) {
$.getJSON("http://example.com/test.html?" + text, null, function (data) {
console.log(data)
}
}

Just create a list of functions:
var duration = 1000; // API duration
var expectAsync = 3000; // time to wait for new functions;
var lastCall = Date.now();
var myArray = ['1','2','3'];
function queryArray() {
var fnList = [];
myArray.forEach(function(v){
fnList.push( function() { // push f1 to list;
$.ajax({
type: "POST",
url: "backend.php",
data: {suburbs : v},
success: function(data){
fnList.push(function(){ // push f2, after we get response;
for (var item in data){
f2(data[item]);
}
})
}
})
});
// here we go;
var int;
int = setInverval(function(){
if(fnList.length){
var fn = fnList.shift(); // pop first function from left;
fn();
}else{
if((Date.now() - lastCall) > expectAsync) clearInterval(int);
}
lastCall = Date.now();
}, duration);
}

setTimeout does not work like java's sleep. It is asynchronous with a callback. After the time is up, the callback function get triggered, which means that you want to put your request into the callback function.
myArray = ['1','2','3'];
function f1(){
for (var i = 0; i < myArray.length; i++){
$.ajax({
type: "POST",
url: "backend.php",
data: {suburbs : myArray[i]},
success: function(data){
for (var j = 0; j < data.length; j++){
setTimeout(function() {
f2(data[j]);
}, (i*data.length + j)*1000);
}
}
});
}
}
In the for loop, you need to use the index to determine how long you need to wait. After the request is triggered.

Related

execute code after AJAX loop finished

I have an AJAX call that gets called "i" amount of times. I want to execute the rest of the code only after the last AJAX processData callback function was finished (It fills values of the .csv into an array called "lines" and I need the finished array after all iterations have finished). So far it only works by using "setTimeout()" which is not a nice solution
for (var i = 0; i < options.length; i++) {
(function(index) {
$.ajax({
type: "GET",
url: options[index] + ".csv",
dataType: "text",
success: function(data) {
processData(data, options[index], type)
}
});
})(i);
}
setTimeout(function() {
getAveragePercentages(lines);
}, 500)
You can use the JavaScript promise functionality.
Make AJAX request in the promise.
Create an array which will contains all these promise.
Promise.all will be executed after all promise get resolved.
var promiseArr = [];
for (var i = 0; i < options.length; i++) {
var promise = new Promise(function(resolve, reject) {
(function(index) {
$.ajax({
type: "GET",
url: options[index] + ".csv",
dataType: "text",
success: function(data) {
processData(data, options[index], type); resolve('outputIfany')
}
});
})(i);
});
promiseArr.push(promise);
}
Promise.all(promiseArr).then(function(values) {
getAveragePercentages(lines);
});
for (var i = 0; i < options.length; i++) {
(function (index) {
$.ajax({
type: "GET",
url: options[index] + ".csv",
dataType: "text",
success: function (data) {
processData(data, options[index], type)
}
});
counter = counter + 1;
})(i);
if (i == options.length) {
getAveragePercentages(lines);
}
}
You can do something like this.
after last Loop Success call function
var totalRec = options.length;
for(var i=0;i<options.length;i++){
(function(index){
$.ajax({
type: "GET",
url: options[index]+".csv",
dataType: "text",
success: function(data) {processData(data, options[index], type)
if(i == (totalRec-1)){
getAveragePercentages(lines);
}
}
});
})(i);
}
or
var totalRec = options.length;
for(var i=0;i<options.length;i++){
(function(index){
$.ajax({
type: "GET",
url: options[index]+".csv",
dataType: "text",
success: function(data) {processData(data, options[index], type)
}
});
})(i);
if(i == (totalRec-1)){
getAveragePercentages(lines); // gets called only when condition is true
}
}
It is not a good practice to use a setTimeOut for wait the ajax call, in my experience I've been using recursive functions for doing this, in your case you can do the following:
var counter = 0;
function main()
{
counter = 0;
doAjaxCall(counter);
}
function doAjaxCall(counter)
{
(function(index){
$.ajax({
type: "GET",
url: options[index]+".csv",
dataType: "text",
success: function(data) {
processData(data, options[index], type);
if(counter < options.length)
{
counter++;
doAjaxCall(counter); //We call the same function but with the next index
}
else
{
//The loop finished, countinue code after your for loop
}
}
});
})(i);
}
set up a counter and check it's value before calling your function
$("#counter").html("0");
for(var i=0;i<options.length;i++){
(function(index){
$.ajax({
type: "GET",
url: options[index]+".csv",
dataType: "text",
success: function(data) {
processData(data, options[index], type)
var counter = $("#counter").html();
if( counter == options.length ){
getAveragePercentages(lines);
}
$("#counter").html(counter+1);
}
});
})(i);
}
I added a function as a parameter. The AJAX calls the function when the load is completed.
function loadDoc(call_back_func) {
const xhttp = new XMLHttpRequest();
xhttp.onload = function() {
json_data = JSON.parse(this.responseText);
call_back_func();
}
xhttp.open("GET", "kanban_personal_template.json");
xhttp.send();
}
function load_call_back()
{
console.log(json_data);
}
loadDoc(load_call_back);

Ajax succes in loop to set global variable

I want to set global variable from function and loop ajax to get distance.
However the nearestIndex variable is always undefined.
First solution I got was to use async: false - this is work in my pc browser, but this project is webservice to android, and this solution not work to webview.
And of course async: false not recommended. I need this example in my case, I've been looking for this problem in stack overflow, but i always failed to understand about callback.
var allDestination = ["A", "B", "C"];
var nearestIndex;
function getNearest(){
var from = myPosition.getLatLng().lat + "," + myPosition.getLatLng().lng;
var tempDistance;
for(var i=0; i<allDestination.length; i++){
var destination = allDestination[i].getLatLng().lat + "," + allDestination[i].getLatLng().lng;
$.ajax({
type: "GET",
url: "http://localhost:8989/route?point=" + from + "&point=" + destination + "&points_encoded=false&instructions=false",
dataType: 'json',
contentType: "application/json",
success: function (data) {
var distance = data.distance;
if(i == 0){
tempDistance = distance;
nearestIndex = i;
} else {
if(distance < tempDistance){
tempDistance = distance;
nearestIndex = i;
}
}
}
});
}
}
function onMapClick(e) {
myPosition.setLatLng(e.latlng);
myPosition.addTo(map);
getNearest();
allDestination[nearestIndex].addTo(map);
}
As you are dealing with Async call; your relevant code has to get called from success handler of ajax call as follows:
var allDestination = ["A", "B", "C"];
var nearestIndex;
var tempDistance;
var successReceived = 0; //counter to keep watch on ajax success callback
//modify the function signature to receive index as well as callback function
function getNearest(index, callbackFunction) {
var from = myPosition.getLatLng().lat + "," + myPosition.getLatLng().lng;
var destination = allDestination[index].getLatLng().lat + "," + allDestination[index].getLatLng().lng;
$.ajax({
type: "GET",
url: "http://localhost:8989/route?point=" + from + "&point=" + destination + "&points_encoded=false&instructions=false",
dataType: 'json',
contentType: "application/json",
success: function(data) {
successReceived++; //increment the success counter
var distance = data.distance;
if (index == 0) {
tempDistance = distance;
nearestIndex = index;
} else {
if (distance < tempDistance) {
tempDistance = distance;
nearestIndex = index;
}
}
//check if we got all the ajax response back. If yes then call the callback function
if(successReceived == allDestination.length && typeof callbackFunction == 'function')
{
callbackFunction();
}
}
});
}
function onMapClick(e) {
myPosition.setLatLng(e.latlng);
myPosition.addTo(map);
for (var i = 0; i < allDestination.length; i++) {
//pass the current index and callback function
getNearest(i,function(){
allDestination[nearestIndex].addTo(map);
});
}
}
I ever have got the same problem like you,
it because asincrounous function cant return anything.
so I think you shoud inject allDestination[nearstIndex].addTo(map); into ajax success
if(i == 0){
tempDistance = distance;
allDestination[i].addTo(map);
} else {
if(distance < tempDistance){
tempDistance = distance;
allDestination[i].addTo(map);
}
}
or you create function to handle ajax success,,, CMIIW

Img Animation with Javascript

Why the timeout don't work?
If i work without the function sleep, they return to me an undefined data..
With this function they work but without sleeping time, they go directly to the last image.. :-/
function sleep(value, data, i) {
document.getElementById(value).src = data[i];
}
function imgAnimation(value){
var img = document.getElementById(value).src;
$.ajax({
type: "POST",
url: "static/cercaThumbs.php",
data: 'id=' + value,
datatype: 'json',
success: function (data) {
var elements = Object.keys(data).length;
for (var i = 0; i < elements; i++) {
if(i == elements){i = 0;}
setTimeout(sleep(value, data, i), 300);
}
}
});
}
You need to pass a function to setTimeout. You're calling the function sleep and passing its result.
setTimeout(function() {
sleep(value, data, i);
}, 300);
But it still won't work, because you're setting a bunch of timeouts at the same time, so they'll all trigger 300ms later at the same time. To animate you might try something like:
var data = [
'https://cdnjs.cloudflare.com/ajax/libs/emojione/2.2.2/assets/png/0030.png',
'https://cdnjs.cloudflare.com/ajax/libs/emojione/2.2.2/assets/png/0031.png',
'https://cdnjs.cloudflare.com/ajax/libs/emojione/2.2.2/assets/png/0032.png',
]
var frame = 0;
var elements = data.length;
var animation = setInterval(function() {
frame = (frame + 1) % elements;
document.getElementById('test').src = data[frame];
}, 300);
<img id=test>
This sets up a single repeating callback which can advance to the next frame each time. In the example above it will loop forever, or you can call clearInterval(animation) once you're finished.
Ok, with the help of Nick, this is the correct code:
function imgAnimation(value){
$.ajax({
type: "POST",
url: "static/cercaThumbs.php",
data: 'id=' + value,
datatype: 'json',
success: function (data) {
var elements = Object.keys(data).length;
var frame = 0;
var animation = setInterval(function() {
frame = (frame + 1) % elements;
document.getElementById(value).src = data[frame];
}, 500);
document.getElementById(value).addEventListener("mouseout", function(){
clearInterval(animation);
document.getElementById(value).src = data['0'];
});
}
});
}

Update textarea after get response from servlet in javascript

I have a program which calls a function in javascript with 1 o more requests to 1 servlet, I want to execute request after request and get the response after each exucution, to make this I have 1 function, but it only shows the result after all requests have been executed.
function cmd(args) {
width = 0;
var res = args.split('\n');
var largo = res.length;
var progressLength = 100 / largo;
for (var i = 0; i < largo; i++)
{
if (res[i] == 'desconectar')
{
desconectar();
break;
}
else
{
executeCMD(res[i]);
}
}
}
function executeCMD(args)
{
$.ajax({
type: "POST",
url: 'Controlador',
data: {cmd: args, operacion: 1},
success: function (response) {
document.getElementById('respuesta').value = document.getElementById('respuesta').value + response;
},
dataType: 'text',
async: false
});
}
If I add window.alert(response); inside success field it shows the progress step by step and works fine, but it show alerts which I don't want.
This is I want http://imgur.com/a/9nclR but I'm getting only last picture.
The solution if anyone is intersting was using a recursive function as next:
function cmd(args) {
width = 0;
move(0);
var res = args.split('\n');
var largo = res.length;
var valInit = 0;
if (largo > valInit)
{
executeCMD(res, valInit);
}
}
function executeCMD(args, i)
{
$(document).ready(function () {
$.ajax({
type: "POST",
url: 'ControladorServlet',
data: {cmd: args[i], operacion: 1, ticket: ticket, iddispositivo: sesion},
success: function (response) {
var textarea = document.getElementById('respuesta');
var res = response.trim().split('\n');
if(error){//dc}
else
{
document.getElementById('respuesta').value = document.getElementById('respuesta').value + response.trim() + "\n\n";
var valor = (100) * (i + 1) / args.length;
move(valor);
if (i + 1 < args.length)
{
executeCMD(args, i + 1);
}
}
},
dataType: 'text'
});
});
}

method is executing before ajax call getting completed

I am trying to call a method after all ajax calls gets completed but some reason the method id getting triggered before one of the ajax call is getting completed. i tried to keep the method in ajax complete section and using $.when() and async:false but i am getting same result. I don't know if its because i am using jsonp ?
My jquery version is 1.11.0
Below is my code
function getBBTrending() {
bbProductD = [];
jQuery.ajax({
type: "GET",
url: "crazycalls/getbbtrending.php",
// cache must be true
cache: true,
crossDomain: true,
success: function (data) {
bbTrending = data.results;
for (var i = 0; i < 4; i++) {
getProductdetails(bbTrending[i].productLink);
}
},
dataType: 'json'
});
}
function getProductdetails(pLink) {
jQuery.ajax({
type: "GET",
url: pLink,
// cache must be true
cache: true,
crossDomain: true,
success: function (data) {
pushArray(bbProductD, data);
},
dataType: 'jsonp'
});
}
function pushArray(array1,data1)
{
array1.push(data1);
}
// this function is executing before pushArray(array1,data1)
jQuery( document ).ajaxStop(function() {
displayProducts(bbProductD);
})
function displayProducts(bbProductD)
{
jQuery("#bbButtongroup").show();
var rProducts = bbProductD;
var rating;
var html = ['<div class="row">']
for (var i = 0; i < rProducts.length; i++)
{
var entry = rProducts[i];
var title = entry.name
var Tnail = entry.image;
var sPrice = entry.salePrice;
var rPrice = entry.regularPrice;
var hcode = '<div class="col-sm-6 col-md-4"><div class="thumbnail"><img style="height: 200px; width: 100%; display: block;" src=\" '+ Tnail + '\" alt="..."><div class="caption"><h3 style="font-size: 14px;">'+ title +'</h3><p><span class="label label-info"> Regular Price : '+ rPrice +'</span></p><p><span style="float: right;" class="label label-info">Sale Price :'+ sPrice +'</span></p><p>BuyView</p></div></div></div>';
html.push(hcode);
}
html.push('</div>');
document.getElementById('pContainer').innerHTML = html.join('');
}
this is how i added using $.when
jQuery.when( { getBBTrending(),getProductdetails()}).done(function() {
displayProducts(bbProductD);
});
any advice?
The asynchronous way, using async library
function getBBTrending() {
bbProductD = [];
jQuery.ajax({
//stuff...
success: function (data) {
bbTrending = data.results;
async.each(bbTrending, function(element, callback){
getProductdetails(element.productLink, callback);
}, function(err){
displayProducts(bbProductD);
});
},
});
}
function getProductdetails(pLink, callback) {
jQuery.ajax({
//stuff
success: function (data) {
pushArray(bbProductD, data);
callback(null);
},
});
}
The promises way, using jQuery.Deferred and jQuery.when
function getBBTrending() {
bbProductD = [];
jQuery.ajax({
//stuff...
success: function (data) {
bbTrending = data.results;
var promises = [];
for (var i = 0; i < bbTrending.length; i++) {
var promise = getProductdetails(bbTrending[i].productLink);
promises.push(promise);
}
jQuery.when.apply(jQuery, promises).then(function(){
displayProducts(bbProductD);
});
},
});
}
function getProductdetails(pLink) {
var promise = jQuery.Deferred();
jQuery.ajax({
//stuff
success: function (data) {
pushArray(bbProductD, data);
promise.resolve();
},
});
return promise;
}
The dirty way. I do not recommend this solution, it has many flaws. Try to use libraries when you need to do asynchronous stuff in order to keep your code maintainable.
var queriesCount, finishedQueriesCount;
function getBBTrending() {
bbProductD = [];
jQuery.ajax({
//stuff...
success: function (data) {
bbTrending = data.results;
queriesCount = 0;
finishedQueriesCount = 0;
for (var i = 0; i < bbTrending.length; i++) {
getProductdetails(bbTrending[i].productLink);
}
},
});
}
function getProductdetails(pLink) {
queriesCount++;
jQuery.ajax({
//stuff
success: function (data) {
pushArray(bbProductD, data);
finishedQueriesCount++;
if(queriesCount == finishedQueriesCount) {
displayProducts(bbProductD);
}
},
});
}
In each case, I pleaced the part of your code that is not significant for the answer by //stuff
Warning This answer has no error handling, it will fail (never call displayProducts(bbProductD);) if you have an ajax error.

Categories