Waiting for two asynchonous requests - javascript

I'm having trouble sending two request in PHP and waiting for both answers. Here is my code :
function getXDomainRequest() {
var xdr = null;
if (window.XDomainRequest) {
xdr = new XDomainRequest();
} else if (window.XMLHttpRequest) {
xdr = new XMLHttpRequest({mozSystem: true});
} else {
alert("Your browser does not support AJAX");
}
return xdr;
}
function sendData() {
var json1= "";
var json2= "";
var xdr = getXDomainRequest();
xdr.onload = function() {
json1 = xdr.responseText;
}
var xdr2 = getXDomainRequest();
xdr2.onload = function() {
json2 = xdr2.responseText;
}
var Id = document.querySelector('#searchField').value;
// Call API
xdr.open("GET", "./dorequest.php?id=" + Id + "&requesttype=player");
xdr.send();
xdr2.open("GET", "./dorequest.php?id=" + Id + "&requesttype=stats");
xdr2.send();
xdr.wait();
// Display results
getHtmlResults(jsonPlayer, jsonStats);
}
As expected here the json1 and json2 are still empty when getHtmlResults is called. I could do it synchronously by calling the xdr2.send() into the xdr.onload and my final function in the xdr2.onload but I want to do it asynchronously to get a better response time.
Thanks !
(any other comment on the code is welcome I'm quite new to php :) )
EDIT :
So I tryied using Ajax and it seems to work :)
var jsonPlayer = "";
var jsonStats = "";
var steamId = document.querySelector('#searchField').value;
$.when(
$.ajax({url: "./dorequest.php?steamid=" + steamId + "&requesttype=playersummary",
success: function(response){ jsonPlayer = response; }}),
$.ajax({url: "./dorequest.php?steamid=" + steamId + "&requesttype=csgostats",
success: function(response){ jsonStats = response; }}) ).done(
function(player, stats) {
getHtmlResults(player, stats);
});

Promises are commonly used as an abstraction to deal with asynchronous processes.
Wrap your AJAX calls in a Promise to do:
var ajax1 = request("stats");
var ajax2 = request("player");
when(ajax1, ajax2).done(function (stats, player) {
console.log(stats, player);
});
Most popular frameworks have a built-in Promise API.

You can send both the calls ASync and have a function in both .onload which checks if the other request has completed. So as soon as one of the onload finds that the other onload is done, you can call the getHtmlResults function.

Related

Capturing async call response in dojo/aspect before

Trying to capture response of a async request in dojo/aspect before() event before handing it off to the original method as below:
aspect.before(ecm.model.SearchTemplate.prototype, "_searchCompleted", function(response, callback, teamspace){
var args = [];
if(response.num_results==0 && isValidQuery){
var args = [];
var requestParams = {};
requestParams.repositoryId = this.repository.id;
requestParams.query = query;
Request.invokePluginService("samplePlugin", "sampleService",
{
requestParams: requestParams,
requestCompleteCallback: lang.hitch(this, function(resp) { // success
//call stack doesnt enter this code block before returning params to the original
//function
resp.repository = this.repository;
args.push(resp);
args.push(callback);
args.push(teamspace);
})
}
);
return args; //args is empty as the response is not captured here yet.
}
});
aspect.around is what you're looking for. It will give you a handle to the original function you can call at will (thus, async at any time you're ready - or never at all).
aspect.around(ecm.model.SearchTemplate.prototype, "_searchCompleted", function advisingFunction(original_searchCompleted){
return function(response, callback, teamspace){
var args = [];
if(response.num_results==0 && isValidQuery){
var args = [];
var requestParams = {};
requestParams.repositoryId = this.repository.id;
requestParams.query = query;
Request.invokePluginService("samplePlugin", "sampleService",
{
requestParams: requestParams,
requestCompleteCallback: lang.hitch(this, function(resp) { // success
//call stack doesnt enter this code block before returning params to the original
//function
resp.repository = this.repository;
args.push(resp);
args.push(callback);
args.push(teamspace);
original_searchCompleted.apply(this,args);
})
}
);
}
}
});

Sending json via ajax in wordpress using Vanilla JS

I am sending a json in my server using vanilla JS and it returns a bad request, it seems the server only wants a key value pair like 'page=pageData&action=act', when i do this it works, but i would want to send data that way. Is there a way to make it possible?
When i try to make it in jquery it works fine.
$('.more-headlines').on('click', function() {
var pageData = $(this).data('page');
var pageURL = $(this).data('url');
var act = 'load_more';
var jsondata = {
page : pageData,
action : act
}
var xhr = new XMLHttpRequest();
xhr.open('POST', pageURL, true);
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.onload = function() {
if (xhr.status >=200 && xhr.status < 400) {
var data = JSON.parse(xhr.responseText);
console.log(data);
} else {
console.log('sad');
}
};
xhr.send(JSON.stringify(jsondata));
});
This is my code in jquery
$('.more-headlines').on('click', function () {
var that = $(this);
pageData = $(this).data('page');
newPage = pageData+1;
pageURL = $(this).data('url');
act = 'load_more';
that.addClass('icon-spin');
that.find('span').html('loading headline');
jsondata = {
page : pageData,
action : act
}
$.ajax ({
type: 'POST',
url: pageURL,
data: jsondata,
success: function(response) {
setTimeout( function () {
that.data('page', newPage);
$('#featureOnDemand ul').append(response);
that.removeClass('icon-spin');
that.find('span').html('See more headlines');
}, 500);
}
});
});
I looked at the network tab in chrome and i saw that the send request becomes a key value pair like 'page=pageData&action=act'.
I am stuck in this part because i want to make a vanilla js ajax request in my project. Any idea would be much appreaciated. Many thanks!
You want to serialize your object data. Here's a helper function you can pass your object into:
var serializeObject = function (obj) {
var serialized = [];
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
serialized.push(encodeURIComponent(key) + '=' + encodeURIComponent(obj[key]));
}
}
return serialized.join('&');
};

How to chain two ajax requests with promises

I am having trouble with ajax/promises. I have two ajax requests total, with the second ajax call relying data to be returned by the first ajax call.
My first ajax call finds Latitude, Longitude, and country code of the value of #search.
My second ajax call finds the weather of that city, but the API URL is dependent on the Latitude, Longitude and country code that my first ajax call returns. So the second ajax call can't be started until the first one is finished.
My logic here is that var ajax1 is assigned a promise, and var ajax2 starts after ajax1.then() checks that ajax1's promise is resolved. Then ajax2 runs and returns another promise. Finally ajax2.done starts after it checks that ajax2's promise is resolved, and then starting my successWeatherFunction().
My problem is that ajax2.done is not working, as the console.log("test") is not showing up on the console. The two earlier console.logs, console.log(info) and console.log(weatherApiUrl) are working.
Thanks!
$("#search").keypress(function(event) {
if (event.which === 13) {
var searchCity = $("#search").val();
var jsonURL = "http://autocomplete.wunderground.com/aq?query=" + searchCity + "&cb=?"
var ajax1 = $.getJSON(jsonURL);
var ajax2 = ajax1.then(function(data) {
var info = [];
info.push(data["RESULTS"][0]["name"]);
info.push(data["RESULTS"][0]["c"]);
info.push(data["RESULTS"][0]["lat"]);
info.push(data["RESULTS"][0]["lon"]);
console.log(info);
var searchLat = info[2];
var searchLng = info[3];
var countryCode = info[1];
if (countryCode === "US") {
var weatherApiUrl = "https://api.forecast.io/forecast/{APIKEY}/" + searchLat + "," + searchLng + "?exclude=minutely" + "&callback=?";
} else {
var weatherApiUrl = "https://api.forecast.io/forecast/{APIKEY}/" + searchLat + "," + searchLng + "?exclude=minutely" + "?units=si" + "&callback=?";
console.log(weatherApiUrl);
}
return $.getJSON(weatherApiUrl);
});
ajax2.done(function(data){
console.log("test");
successCityWeather(data);
});
Your code use then and done. done is the old promises jQuery syntax so you should use only then.
The following code works for me :
$(function() {
$.get('/test').then(function() {
console.log('First request end');
return $.get('/test');
}).then(function() {
console.log('second request end');
});
});
But in your case, maybe a one of your request fail. Give a second parameter to then to log the error :
$.getJSON('...').then(function(data) {
console.log('success', data);
}, function(data) {
console.log('fail', data);
});
If not sure, always use always() handler. That way you will know if the request actually finished with error or not at all.
$.ajax( ...params... )
.always(function(jqXHR, textStatus) {
if (textStatus != "success") {
alert("Error: " + jqXHR.statusText); //error is always called .statusText
} else {
alert("Success: " + jqXHR.response); //might not always be named .response
}});
$.post(jsonURL)
.then(function (data) {
var info = [];
// some actions
return $.getJSON(weatherApiUrl);
})
.then(function(data, status, promise) {
// some actions
successCityWeather(data);
})

How do I wait for a .each loop that makes async calls?

I have some javascript code that updates some data to a database using a http handler, but this async call is made inside an .each loop. At the end of the loop I make a call to function CancelChanges() that refreshed the page. The problem is that the page seems to refresh before the database is updated. The .each loop seems to finish after the call to CancelChanges(). How can I make sure the page is refreshed after all the async calls are completed in the .each loop?
function SaveChanges() {
if (PreSaveValidation()) {
var allChangesSucceeded = true;
var studioId = $("#param_studio_id").val();
var baseDate = $("#param_selected_month").val().substring(6, 10) + $("#param_selected_month").val().substring(0,2);
var currency = "CAD";
var vacationPct = null;
var gvAdmissible = null;
$(".editable-unsaved").each( function() {
var newSalary = $(this).text();
var disciplineId = $(this).data("disciplineid");
var seniorityId = $(this).data("seniorityid");
var handlerCommand = "";
if ($(this).data("valuetype") === "inflated") {
handlerCommand = "AddAverageSalary";
} else if ($(this).data("valuetype") === "actual") {
handlerCommand = "UpdateAverageSalary";
}
$.get("WS/AverageSalary.ashx", { command: handlerCommand, studio_id: studioId, discipline_id: disciplineId, seniority_id: seniorityId, base_date: baseDate, currency: currency, salary: newSalary, vacation_pct: vacationPct, gv_admissible: gvAdmissible }).done(function (data) {
if (data != "1") {
$(this).removeClass("editable-unsaved");
allChangesSucceeded = true;
}
else {
alert('fail');
allChangesSucceeded = false;
}
});
});
if(allChangesSucceeded) CancelChanges();
}
}
function CancelChanges() {
var href = window.location.href;
href = href.split('#')[0];
window.location.href = href;
}
You could try using Promises and jQuery $.when
Store a list of the ajax call promises:
var defereds = [];
$(".editable-unsaved").each( function() {
//...
defereds.push($.get("WS/AverageSalary.ashx" /*...*/));
}
$.when.apply($, defereds).done(function() {
CancelChanges();
});
This should, hopefully, wait for all the ajax calls to finish before calling CancelChanges()
I think you need to change your structure a little bit, using a counter and calling CancelChanges when the counter equals the number of calls.
function SaveChanges() {
if (PreSaveValidation()) {
var studioId = $("#param_studio_id").val();
var baseDate = $("#param_selected_month").val().substring(6, 10) + $("#param_selected_month").val().substring(0,2);
var currency = "CAD";
var vacationPct = null;
var gvAdmissible = null;
var editableUnsaveds = $(".editable-unsaved"); //cache the selector here, because selectors are costly
var numOfGetsReturned = 0;
editableUnsaveds.each( function() {
var newSalary = $(this).text();
var disciplineId = $(this).data("disciplineid");
var seniorityId = $(this).data("seniorityid");
var handlerCommand = "";
if ($(this).data("valuetype") === "inflated") {
handlerCommand = "AddAverageSalary";
} else if ($(this).data("valuetype") === "actual") {
handlerCommand = "UpdateAverageSalary";
}
$.get("WS/AverageSalary.ashx", { command: handlerCommand, studio_id: studioId, discipline_id: disciplineId, seniority_id: seniorityId, base_date: baseDate, currency: currency, salary: newSalary, vacation_pct: vacationPct, gv_admissible: gvAdmissible }).done(function (data) {
if (data != "1") {
$(this).removeClass("editable-unsaved");
}
else {
alert('fail');
}
if(editableUnsaveds.length === ++numOfGetsReturned){
CancelChanges(); //now it should call when the final get call finishes.
}
});
});
}
}
function CancelChanges() {
var href = window.location.href;
href = href.split('#')[0];
window.location.href = href;
}
I'd use promises. The q library is my favorite way to implement them. But since you're using JQuery, I'd recommend following a similar approach to what I outline below, but using $.when, instead of q.allSettled
I often use promises when scraping tons of websites at once -- I need to iterate through a long list of websites, make requests for content, and do something with the content when the requests return. The last thing I want to do is send requests one at a time, handling each one as it returns.
In the abstract, that looks something like this:
function scrapeFromMany() {
var promises = [];
_.forEach(urls, function(url) {
// this makes the request
var promise = scraper(url);
// this stores the promise with the others you iterate through
promises.push(promise);
});
q.allSettled(promises).then(function(res) {
// this function is executed when all of the promises (requests) have been resolved
console.log("Everything is done -- do something with the results.", res);
});
}
Fwiw, promises aren't that easy to grok if you've never used them. If that's the case, plan on spending some time getting up to speed with the concepts. They'll change (for the much much better) the way you write async javascript, and they really are the blessed path with these sorts of operations.
Asynchronously call your check function within the "done" function handler. Keep track of how many requests have completed, and only do your processing once that's equal to the total number of expected requests.
if (PreSaveValidation()) {
var allChangesSucceeded = true;
var length = $(".editable-unsaved").length;
var completedCount = 0;
// ...
$(".editable-unsaved").each( function() {
// ...
$.get("WS/AverageSalary.ashx", data).done(function (data) {
completedCount++;
if (data != "1") {
$(this).removeClass("editable-unsaved");
// don't set all changes succeeded to true here
}
else {
alert('fail');
allChangesSucceeded = false;
}
isComplete(length, completedCount, allChangesSucceeded);
});
});
}
function isComplete(totalLength, currentLength, allChangesSucceeded) {
if (currentLength == totalLength) {
// should this be !allChangesSucceeded?
if (allChangesSucceeded) CancelChanges();
}
}
This happens because you are not waiting for the requests to complete to proceed with the loop.
To achieve so you have to set the "async" flag to false.
The call to the server should be like this:
$.ajax({
url: "WS/AverageSalary.ashx",
async: false,
data:{ command: handlerCommand, studio_id: studioId, discipline_id: disciplineId, seniority_id: seniorityId, base_date: baseDate, currency: currency, salary: newSalary, vacation_pct: vacationPct, gv_admissible: gvAdmissible },
success: function (data) {
if (data != "1") {
$(this).removeClass("editable-unsaved");
allChangesSucceeded = true;
}
else {
alert('fail');
allChangesSucceeded = false;
}
}
});

javascript callback function call itself until true

I am running a function that i need to keep running until i get a response example
exports.getJson = function(url, callback) {
var loader = Titanium.Network.createHTTPClient();
loader.open("GET", url);
loader.onload = function() {
var response = JSON.parse(this.responseText);
callback(response);
};
loader.onerror = function(e) {
callback(false);
};
// Send the HTTP request
loader.send();
}
ok the problem i am having is it will sometimes give me a response of null and i need it to run again.
so i am calling it like this.
url = 'http://example.com/test.json';
main.getJson(url, function(response) {
if(response){
addData(response);
}else{
//return no response i need to run the function again now until it comes back as true
}
});
Can anyone give me a good way to do this maybe try at least 3 times then return false???
Thanks
Just put the code in function and call it again:
var counter = 0;
function getData() {
main.getJson('http://example.com/test.json', function(response) {
if(response){
addData(response);
}
else if (counter < 3) {
counter++;
getData();
}
});
});

Categories