Multiple AJAX calls without blocking - javascript

I run a function called checker every 60 seconds like so:
setInterval( checker, 60 * 1000 );
checker has an array of URLs which it checks via AJAX, the current code is like this:
$.ajax({
url: sites[i].url,
type: "GET",
dataType: "json",
async: false,
success: function(data){
//blah blah blah
}else{
//something else
},
error: function(){
//blah blah blah
}
});
The code works, changes some UI based stuff depending on the results of the JSON. My problem is that the execution time for this checking several sites is ~4 seconds, at which point the page becomes unresponsive for this time. If I remove async: false the code no longer works as expected.
Someone mentioned using callbacks to solve the problem but don't understand how to use them in this context.
EDIT
Updated code based upon suggestion from adosan:
function promtest(){
var sites = [
{ name: "WorkingSite", url: "http://sitename.com/testing.php" },
//a bunch more sites, 1 returns a 404 to test for failure
{ name: "404Site", url: "http://404url.com/testing.php" }
];
var promiseList = [];
for(var i in sites){
var promise = $.ajax({
url: sites[i].url,
type: "GET",
dataType: "json",
async: true,
success: function(data){
if( data.Response != 'OK' ){
console.log('Site ' + sites[i].name + ' Not OK' );
}else{
console.log( 'Site ' + sites[i].name + ' OK ');
}
},
failure: function(data){
console.log('Failure for site: ' + sites[i].name);
},
error: function(){
console.log('Site ' + sites[i].name + ' Not OK' );
}
});
promiseList.push(promise);
}
$.when.apply($, promiseList).then(function(){console.log('success')}, function(){console.log('fail')});
}
In the console I see:
Site 404Site Not OK
Site 404Site Not OK
Site 404Site Not OK
Site 404Site Not OK
Site 404Site Not OK
Site 404Site Not OK
Site 404Site Not OK
fail
Site 404Site Not OK
Site 404Site Not OK
Site 404Site Not OK
Site 404Site Not OK
Note that the site name is always showing as the last one on the list.

You may use Promise (https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise) here. Example:
function checker(url) {
return new window.Promise(function (resolve, reject) {
function successCallback(response) {
resolve(response);
}
function errorCallback(response) {
reject(response);
}
$.ajax({
data: data,
dataType: 'JSON',
type: 'GET',
url: url
})
.done(successCallback)
.fail(errorCallback);
});
}
function checkerSuccess(response) {
console.log(response);
}
function checkerError(error) {
console.warn(error);
}
checker('http://api.example.com').then(checkerSuccess).catch(checkerError);

You can use jQuery built in deferred mechanism (a promise).
https://api.jquery.com/category/deferred-object/
jQuery.ajax function does return a promise object which can be asigned to a variable.
https://api.jquery.com/jQuery.ajax/
var promise = $.ajax({
url: sites[i].url,
type: "GET",
dataType: "json",
async: true
});
The nice thing about promises is that you can combine multiple promisses into bigger one.
var promiseList = [];
promiseList.push(promise);
$.when.apply($, promiseList).then(function(){/*SUCCESS*/}, function(){/*FAILURE*/});
Complete code should look like so:
var promiseList = [];
for(var i in sites){
var promise = $.ajax({
url: sites[i].url,
type: "GET",
dataType: "json",
async: true
});
promiseList.push(promise);
}
$.when.apply($, promiseList).then(function(){/*SUCCESS*/}, function(){/*FAILURE*/});

I would try this one.
Let's say that the object that you want to be updated is the var foo:
var foo = "";
$.ajax({
url: sites[i].url,
type: "GET",
dataType: "json",
async: false,
success: function(data){
foo = data.gottenValue1
}else{
//something else
},
error: function(){
//blah blah blah
}
});

Related

Assign function to value in Javascript

Good Day,
I try to assign to a variable the result of an Ajax request. I tried both of the requests below, with no result (got an "Undefined" answer).
I don't understand the difference between:
var temp = obj.method(me, you);
and
var temp = (function () {
obj.method(me, you);
})();
Here is the AJAX request:
ObjID.prototype.getAjx = function(one, you){
$.ajax({
type: "post",
url: "./php/getAJX.php",
dataType: 'json',
context: this,
data: { one: one, two: two },
success: function(data) {
this.myProperty = data[0][0];
},
error:function(request, status, error) {
console.log("Something went wrong." + request.responseText + status + error);
}
});
}
Is this the same, or not ?
Thanks for your help! :)
The first two bits of code you showed effectively do the same thing.
However, neither of them do what you think they do. Neither of them are assigning the return value from your AJAX call anywhere:
The first line of your code:
ObjID.prototype.getAjx = function(one, you){
is simply assigning the function that contains the actual AJAX call to the .getAjx property of the ObjID.prototype. That function doesn't contain any return statements and upon execution, will not return anything. That is why you are getting undefined.
The code that actually performs the AJAX call is:
$.ajax({
type: "post",
url: "./php/getAJX.php",
dataType: 'json',
context: this,
data: { one: one, two: two },
success: function(data) {
this.myProperty = data[0][0];
},
error:function(request, status, error) {
console.log("Something went wrong." + request.responseText + status + error);
}
});
and, you aren't assigning that return value to anything. If you wanted to, you'd need to write something like this:
var result = $.ajax({
type: "post",
url: "./php/getAJX.php",
dataType: 'json',
context: this,
data: { one: one, two: two },
success: function(data) {
this.myProperty = data[0][0];
},
error:function(request, status, error) {
console.log("Something went wrong." + request.responseText + status + error);
}
});
JQuery AJAX calls return a reference to a Promise object and that's what you would be storing in that case.

How to force $ajax to wait for data and assign these to a variable?

I have trouble async disable ajax. I have the following code:
function GetDataFromUninorte() {
link="http://www.uninorte.edu.co/documents/71051/11558879/ExampleData.csv/0e3c22b1-0ec4-490d-86a2-d4bc4f512030";
var result=
$.ajax({
url: 'http://whateverorigin.org/get?url=' + link +"&callback=?" ,
type: 'GET',
async: false,
dataType: 'json',
success: function(response) {
console.log("Inside: " + response);
}
}).responseText;
console.log("Outside: "+result);
return result;
}
And I get the following result:
"Outside" always runs first
As you can see, "Outside" always runs first and the result is undefined and can not process data.
I have already tried
When ... Then
Async = false
passing data as parameters I / O function
and other things, but nothing
:/
... Beforehand thank you very much
(I am not a native english speaker, I apologize if I do not write well)
[Solved]
Maybe is not the best form, but in the "success:" statement I call a function that receive the ajax response and trigger the rest of the process, in this way I not need store the in a variable and the asynchrony not affect me.
Use can use callbacks, you can read more here
function GetDataFromUninorte(successCallback, errorCallback) {
link="http://www.uninorte.edu.co/documents/...";
$.ajax({
url: 'http://whateverorigin.org/get?url=' + link +"&callback=?" ,
type: 'GET',
async: false,
dataType: 'json',
success: successCallback,
error: errorCallback
});
}
function mySuccessCallback(successResponse) {
console.log('callback:success', successResponse);
}
function myErrorCallback(successResponse) {
console.log('callback:success', successResponse);
}
GetDataFromUninorte(mySuccessCallback, myErrorCallback);
Or you can use promises (bad support in IE browsers)
function GetDataFromUninorte() {
return new Promise(function(resolve, reject) {
link="http://www.uninorte.edu.co/documents/...";
$.ajax({
url: 'http://whateverorigin.org/get?url=' + link +"&callback=?" ,
type: 'GET',
async: false,
dataType: 'json',
success: resolve,
error: reject
});
});
}
GetDataFromUninorte()
.then(function(successResponse){
console.log('promise:success', successResponse);
}, function(errorResponse){
console.log('promise:error', errorResponse);
});
AJAX being asynchronous by nature, you need to pass callback, which will be called when the ajax response is received. You may then access responseText from the xhr object.
You can also you jQuery Deferred and promise to get around your problem like below:
function GetDataFromUninorte() {
var defObject = $.Deferred(); // create a deferred object.
link="http://www.uninorte.edu.co/documents/71051/11558879/ExampleData.csv/0e3c22b1-0ec4-490d-86a2-d4bc4f512030";
$.ajax({
url: 'http://whateverorigin.org/get?url=' + link +"&callback=?" ,
type: 'GET',
async: false,
dataType: 'json',
success: function(response) {
console.log("Inside: " + response);
defObject.resolve(response); //resolve promise and pass the response.
}
});
return defObject.promise(); // object returns promise immediately.
}
and then:
var result = GetDataFromUninorte();
$.when(result).done(function(response){
// access responseText here...
console.log(response.responseText);
});
You should avoid making AJAX synchronous by setting async:false as that will block further interactions on the User Interface.
Use this:
function GetDataFromUninorte() {
link="http://www.uninorte.edu.co/documents/71051/11558879/ExampleData.csv/0e3c22b1-0ec4-490d-86a2-d4bc4f512030";
var result=
$.ajax({
url: 'http://whateverorigin.org/get?url=' + link +"&callback=?" ,
type: 'GET',
**timeout: 2000,**
async: false,
dataType: 'json',
success: function(response) {
console.log("Inside: " + response);
}
}).responseText;
console.log("Outside: "+result);
return result;
}

AJAX GET returns undefined on the first call, but works on the second one

I am working on a real estate web app in ASP.NET MVC. My problem is in my Reservations section.
I am using AJAX to post in a Controller which returns a JSONResult. Here is my code:
Controller
[HttpPost]
public JsonResult SubmitReservation(ReservationViewModel rvm)
{
return Json(rvm, JsonRequestBehavior.AllowGet);
}
Main AJAX
var rvm = new ReservationViewModel();
getBuyerInfo(rvm.SelectedBuyerID, clientCallback);
getSiteInfo(rvm.SelectedSiteID, siteCallback);
getUnitInfo(rvm.SelectedUnitID, unitCallback);
$.ajax({
url: "/Reservations/SubmitReservation",
data: JSON.stringify(rvm),
type: "POST",
dataType: "json",
contentType: "application/json",
success: function () {
console.log(clientData);
console.log(siteData);
console.log(unitData);
//Assignment of data to different output fields
//Client Data
$('#clientName').html(clientData.FullName);
$('#clientAddress').html(clientData.Residence);
$('#clientContact').html(clientData.ContactNumber);
//Site Data
$('#devSite').html(siteData.SiteName);
$('#devLoc').html(siteData.Location);
////House Unit Data
$('#unitBlock').html(unitData.Block);
$('#unitLot').html(unitData.Lot);
$('#modelName').html(unitData.ModelName);
$('#modelType').html(unitData.TypeName);
$('#lotArea').html(unitData.LotArea);
$('#floorArea').html(unitData.FloorArea);
$('#unitBedrooms').html(unitData.NumberOfBedrooms);
$('#unitBathrooms').html(unitData.NumberOfBathrooms);
$('#unitPrice').html(unitData.Price);
$('#reservationDetails').show();
alert("Success!");
},
error: function (err) {
alert("Error: " + err);
}
});
Functions for fetching data
function getBuyerInfo(id, cb) {
$.ajax({
url: "/BuyersInformation/GetBuyerByID/" + id,
type: "GET",
contentType: "application/json",
dataType: "json",
success: cb
});
}
function getSiteInfo(id, cb) {
$.ajax({
url: "/Sites/GetSiteByID/" + id,
type: "GET",
contentType: "application/json",
dataType: "json",
success: cb
});
}
function getUnitInfo(id, cb) {
$.ajax({
url: "/HouseUnits/GetUnitByID/" + id,
type: "GET",
contentType: "application/json",
dataType: "json",
success: cb
});
}
function ReservationViewModel() {
var buyerId = $('#SelectedBuyerID').val();
var siteId = $('#SelectedSiteID').val();
var unitId = $('#SelectedUnitID').val();
var rsvDate = $('#ReservationDate').val();
var me = this;
me.ReservationDate = rsvDate;
me.SelectedBuyerID = buyerId;
me.SelectedSiteID = siteId;
me.SelectedUnitID = unitId;
}
function clientCallback(result) {
clientInfo = result;
clientData = clientInfo[0];
}
function siteCallback(result) {
siteInfo = result;
siteData = siteInfo[0];
}
function unitCallback(result) {
unitInfo = result;
unitData = unitInfo[0];
}
The whole code WORKS well for the second time. However, it does not work for the FIRST time. When I refresh the page and I hit Create, it returns undefined. But when I hit that button again without refreshing the page, it works well. Can somebody explain to me this one? Why does AJAX returns undefined at first but not at succeeding calls? Thanks in advance.
You are calling several ajax requests in your code, inside these functions:
getBuyerInfo(rvm.SelectedBuyerID, clientCallback);
getSiteInfo(rvm.SelectedSiteID, siteCallback);
getUnitInfo(rvm.SelectedUnitID, unitCallback);
and finally $.ajax({...}) after them, where you use results from pervious ajax calls.
Your problem is that the first ajax calls do not necessarily return results before your start the last ajax because they are all async. You have to make sure you get three responds before calling the last ajax. Use promises or jQuery when, like this:
var rvm = new ReservationViewModel();
$.when(
$.ajax({
url: "/BuyersInformation/GetBuyerByID/" + rvm.SelectedBuyerID,
type: "GET",
contentType: "application/json",
dataType: "json"
}),
$.ajax({
url: "/Sites/GetSiteByID/" + rvm.SelectedSiteID,
type: "GET",
contentType: "application/json",
dataType: "json"
}),
$.ajax({
url: "/HouseUnits/GetUnitByID/" + rvm.SelectedUnitID,
type: "GET",
contentType: "application/json",
dataType: "json"
})
).done(function ( clientResponse, siteResponse, unitResponse ) {
clientInfo = clientResponse;
clientData = clientInfo[0];
siteInfo = siteResponse;
siteData = siteInfo[0];
unitInfo = unitResponse;
unitData = unitInfo[0];
$.ajax({ ... }) // your last ajax call
});
AJAX calls are asynchronous. You last ajax call will not wait until your above 3 ajax calls finishes its work. so you can make use of $.when and .done here as below..
$.when(
getBuyerInfo(rvm.SelectedBuyerID, clientCallback);
getSiteInfo(rvm.SelectedSiteID, siteCallback);
getUnitInfo(rvm.SelectedUnitID, unitCallback);
).done(
$.ajax({
//Ajax part
})
);

Architecture for Multiple API Calls Using jQuery and Javascript

Curious about what others see as the best way to architect making an API call that depends on the response of another API call in jQuery.
Steps:
Make an API JSONP call to an endpoint, receive response
If we get a 200 success response from the first call, we would trigger another API call (JSON this time).
Output results into browser.
This is how I would construct it with some crude error handling:
$(document).ready(function() {
$.ajax({
url: "http://example.com/json",
type: 'POST',
dataType: 'jsonp',
timeout: 3000,
success: function(data) {
// Variables created from response
var userLocation = data.loc;
var userRegion = data.city;
// Using variables for another call
$.ajax({
url: "http://example2.com/json?Location=" + userLocation + "&City=" + userRegion,
type: 'POST',
dataType: 'json',
timeout: 3000,
success: function(Response) {
$(.target-div).html(Response.payload);
},
error: {
alert("Your second API call blew it.");
}
});
},
error: function () {
alert("Your first API call blew it.");
}
});
});
In terms of architecture, you may consider using Promise pattern to decouple each step into one function, each function cares only about it's own task (do not reference to another step in the flow). This gives more flexibility when you need to reuse those steps. These individual step can be chained together later on to form a complete flow.
https://www.promisejs.org/patterns/
http://api.jquery.com/jquery.ajax/
http://api.jquery.com/category/deferred-object/
function displayPayload(response) {
$(".target-div").html(response.payload);
}
function jsonpCall() {
return $.ajax({
url: "http://example.com/json",
type: 'GET',
dataType: 'jsonp',
timeout: 3000
});
}
function jsonCall(data) {
// Variables created from response
var userLocation = data.loc;
var userRegion = data.city;
// Using variables for another call
return $.ajax({
url: "http://example2.com/json?Location=" + userLocation + "&City=" + userRegion,
type: 'GET',
dataType: 'json',
timeout: 3000
});
}
$(document).ready(function() {
jsonpCall()
.done(function(data) {
jsonCall(data)
.done(function(response) {
displayPayload(response);
}).fail(function() {
alert("Your second API call blew it.");
});
}).fail(function() {
alert("Your first API call blew it.");
});
});

JQuery Ajax call, return value problem

function getMore(from){
var initData = "&start-index=";
initData += from;
$.ajax({
type:"POST",
url: '', //removed the URL
data: initData,
dataType: 'json',
success: function(result) {
return result;
},
error: function(errorThrown) {
}
});
return result;
}
Its a google base query; I have another function that makes the initial server call and gets the first 250 items. I then have a running counter and as long as the results = 250 it calls the server again, but starting at "start-index=" of the current amount of items pulled off. This part all works correctly and with firebug I can also see that the server response is proper JSON.
The trouble I'm having is trying to return the JSON from this function to the function that called it. I do not want to call the original function again because it will clear the arrays of data already pulled from the server. Each time it returns to the parent function it's null.
Does anyone know how i can go about returning the data using "return"?
function FuncionCallGetMore(){
//...
getMore('x-value', FuncionGetReturn);
//...
}
function FuncionGetReturn(error, value){
if (!error) {
// work value
}
}
function getMore(from, fn){
var initData = "&start-index=" + from;
$.ajax({
type:"POST",
url: '', //removed the URL
data: initData,
dataType: 'json',
success: function(result) {
fn(false, result);
},
error: function(errorThrown) {
fn(true);
}
});
return;
}
The only way that you can do what you're describing is to make the AJAX call synchronous, which you don't want to do since it will lock the UI thread while the request is being made, and the browser may will to freeze. No one likes freezing.
What you want to do is use callbacks. Post the code of the other functions involved so I can get a better idea of what is going on. But basically, what you want to do is to create an asynchronous loop.
function listBuilder() {
var onError = function(response) {
// ...
};
var onSuccess = function(response) {
// Handle the items returned here
// There are more items to be had, get them and repeat
if ( response.length == 250 ) {
getMore(onSuccess, onError, 250);
}
};
getInitialSet(onSuccess, onError);
}
function getMore(onSuccess, onError, from) {
$.ajax({
type:"POST",
url: '', //removed the URL
data: "&start-index=" + from,
dataType: 'json',
success: onSuccess,
error: onError
});
}

Categories

Resources