Use data from ajax call without using async: false - javascript

I'm pretty new to JS/ajax and was a bit confused on ajax data/success returns.
I have the following ajax code. I want it to run the code in succes: after the ajax call has received the json from the imgur api.
It is only working for me with async: false. I thought the bit in success: would only run after the data has been retrieved, but for some reason data is null if aysnc is true.
I've read a lot of SO answers/jQuery documentation but I can't seem to figure out how to get it to not hang the browser with async: false
This code might be running 100+ times on a page (i.e. reddit.com/r/pics with 100 links loaded on one page), so async: false is not only bad practice but also renders the page unusable for 5 to 6 seconds, which is unacceptable.
I've tried making ajax a var then calling that var .success(function(data) ...); but it still does not work. I've also tried replacing success with complete.
It all only ever works with async: false
Any suggestions would be greatly appreciated!
Thanks!
$.ajax({
type: "GET",
url: "https://api.imgur.com/3/gallery/" + hash,
dataType: "json",
headers:{
'Authorization':'Client-ID c606aeeec9ca098'
},
async: false,
success: function(data) {
if(data.data.is_album == true) {
if(data.data.images_count == 1){
el[j].href = el[j].href.replace(/(http(s)?:\/\/)?(www\.)?(m\.)?imgur.com\/gallery\/.*/, data.data.images[0].link);
}else{
el[j].href = el[j].href.replace(/(http(s)?:\/\/)?(www\.)?(m\.)?imgur.com\/gallery\//, "https://imgur.com/a/");
}
}
else{
el[j].href = el[j].href.replace(/(.*)?(http(s)?:\/\/)?(www\.)?(m\.)?imgur.com\/.*/, data.data.link);
}
}
});

You might find the jQuery Deferred object (Promises interface) to be helpful. It allows you to do stuff like:
var promise = $.ajax("/myServerScript1");
function getStuff() {
return $.ajax("/myServerScript2");
}
promise.then(getStuff).then(function(myServerScript2Data){
// Do something with myServerScript2Data
});
Resource (this is well written and a necessary read for anyone using AJAX):
http://www.htmlgoodies.com/beyond/javascript/making-promises-with-jquery-deferred.html

I can't see what doesn't work on your code but I can tell you what is not recommended.
Always have a failure handler : You have to put a function in the fail field of your request object. If you don't, you will not be able to see any errors.
Keep the test simple : You should begin by only displaying the value of the request result instead making some calculation with it. This way you can debug ONLY the request call and you are sure that the problem doesn't came from the calculation code
Use Promises API : As previously pointed by the #gibberish, the modern way to do what you want is to use Promises. You can use jQuery's promises or any other like ES6 Promises (that one requires a compilation time for most of browsers)

Related

Ajax file upload returns status code 0 ready state 0 (only sometimes)

I have looked at the following thread
jQuery Ajax - Status Code 0?
However I could not find a definitive answer and I am having serious trouble trying to find the source of my issue so I am posting here in the hopes that someone can point me in the right direction.
In my code I am performing an Angular HTTP post which just sends basic JSON data, then within the on success callback I am using AJAX to upload files to the same server. (I know I should not be using jQuery and Angular however I can't change this for the moment)
It looks something like this
var deferred = $q.defer()
// first post
$http.post(url,payload,{params: params, headers: headers)
.then(function(response) {
uploadFiles(response,deferred);
// I am also sending google analytics events here
}, function(error) {
// do error stuff
}
return deferred.promise;
// upload files function
function uploadFiles(response,deferred){
$ajax({
type: 'POST',
processData: false,
contentType: false,
data: data // this new FormData() with files appended to it,
url: 'the-endpoint-for-the-upload',
dataType: 'json',
success: function(data) {
// do success stuff here
deferred.resolve(data);
},
error: function(jqXHR, textStatus, errorThrown) {
var message = {};
if (jqXHR.status === 0) {
message.jqXHRStatusIsZero = "true";
}
if (jqXHR.readyState === 0) {
message.jqXHRReadyStateIsZero = "true";
}
if (jqXHR.status === '') {
message.jqXHRStatusIsEmptyString = "true";
}
if (jqXHR.status) {
message.jqXHRStatus = jqXHR.status;
}
if (jqXHR.readyState) {
message.jqXHRReadyState = jqXHR.readyState;
}
if (jqXHR.responseText) {
message.jqXHR = jqXHR.responseText;
}
if (textStatus) {
message.textStatus = textStatus;
}
if (errorThrown) {
message.errorThrown = errorThrown;
}
message.error = 'HTTP file upload failed';
logError(message);
deferred.resolve(message);
}
}
})
}
Not my exact code but almost the exact same.
The issue is that is works almost all of the time, but maybe three or four in every few hundred will fail. By fail I mean the error handler function is called on the file upload function and the files are not uploaded.
I get jqXHRStatus 0 and jqXHRReadyState 0 when this occurs.
The only way I am able to replicate the issue is by hitting the refresh on the browser when the request is being processed, however users have advised they are not doing this (although have to 100% confirm this)
Is there perhaps a serious flaw in my code which I am not seeing? Maybe passing deferred variable around isn't good practice? Or another way the ajax request is being cancelled that I am not considering? Could sending google analytics events at the same time be interfering?
Any advice would be great and please let me know if you would like more information on the issue.
This means, the request has been canceled.
There could be many different reasons for that, but be aware: this could be also due to a browser bug or issue - so i believe (IMHO) there is no way to prevent this kind of issues.
Think for example, you get a 503 (Service Unavailable) response. What you would do in such a case? This is also a sporadic and not predictable issue. Just live with that, and try to repost your data.
Without reinventing the wheel, I suggest you to implement:
Retrying ajax calls using the deferred api
My guess is that your code is executing before it actually gets back from the call. I.e. the call goes back and nothing was returned and it gives a 0 error. This would make sense as the error is variable. Most of the time it would return fine because the backend executed fast enough but sometimes it wouldn't because it took especially long or something else happened etc. Javascript doesn't ever REALLY stop execution. It says it does but especially passing between angular and jquery with multiple ajax requests it wouldn't be surprising if it was executing the second ajax call before it actually completed your angular post. That's why a refresh would replicate the error because it's would clear your variables.
Some things you can do to test this:
On the backend make a timer that goes for a few seconds before it returns anything. This will probably make your code fail more consistently.
Set breakpoints and see when they are being hit and the values they contain in the javascript.
Good luck!

Syncronous XMLHTTPRequest deprecated crash browser?

I have to read information as below from a microprocessor hardware
var save_it = '';
$.ajax({
type: "GET",
url: 'http://www.micro-processor-server/?ROBOT=arm_controle',
async: false,
success:function(m) {
save_it = m;
}
}).responseText;
console.log(save_it);
While doing so, it works, but my browser console gives very scary warning as below, also several times I have noticed web-browser Google chrome get hang:
Can anyone please show an alternative way how to make my Ajax query compatible? (I can't change codes in Micro-processor its third party robot)
Put the code that needs the response in the success function. You could also use $.get if this is all you're needing to do.
$.get('http://www.micro-processor-server/?ROBOT=arm_controle', function(data) {
console.log(data);
});
call another function with return data.
$.get('http://www.micro-processor-server/? ROBOT=arm_controle',function(data){
myfun(data);
});
myfun(data){
console.log(data);//here you might be able get rid of asynchronous behaviour.
}

Asynchronous Lazy Loading

currently, we are using the SAP HANA Database. To get data, we will use a Node.JS-API, which we will call via AJAX, to get the advantages by async. So here is the problem:
We have many pages where we need the same data (e.g. customer data). To do so, I wanted to create a Library, which does the actual data calls, so that i just need to call db.getCustomer([ID]). In order to get a return value from AJAX, I have to set async: false within the AJAX call.
My question is now, is it possible to create a data-call-library asynchronously? Is it a good practice to encapsulate the databinding (using so called DAO)?
I'm a bit confused, because another dev told me to just use the same AJAX-call over and over again, to not loose the async and it is a better practice anyway.
Here is my actual AJAX-call as an example:
getCustomer: function( CID ) {
var aUrl = 'http://example.com/api/customer/' + CID,
returnData
;
jQuery.ajax({
url: aUrl,
method: 'GET',
dataType: 'json',
contentType: "application/json",
async: false,
success: function(data) {
returnData = data;
}
});
return returnData;
},
// other ajax calls
// to get the data via 1-liner
thank you for clarification!
Actually, it makes no sense to return data from a callback in a synchronous function; normally, you would store the returned callback data into your model, so your view/controller gets automatically updated.
If you really need your method to return async data, have a look at Deferred or Promises

execute a PHP script from Ajax without expecting an answer (and no daemons)

I hope you can help me with this issue:
My sistem runs over Zend Framework, I have installed jQuery in it's latest version. I have an input that receives a file and it makes an Ajax call when changes, and I want that call made in the background, without expecting any response (because that script will send an email when finished). My ajax call is like this:
var formData = new FormData();
formData.append('file', $(this).get(0).files[0]);
$.ajax({
url: 'uploadaddresses.php',
type: 'POST',
data: formData,
dataType: 'json',
async:true,
processData: false,
contentType: false,
beforeSend: function(){
bootbox.alert("You've made your petition correctly. When finished, an email will be sent to you.")
},
error: function(err) {}
});
return false;
Although, the call waits for a response (even FireBug shows me that uploadaddresses.php is still executing...). What i'm doing wrong? How should I do it best? I want to avoid using daemons and system calls, because system restrictions...
Thank you very much in advance :)
If you're wanting uploadaddresses.php to return an HTTP response immediately but continue processing, take a look at pcntl_fork in PHP.
Here's the main doc page: http://php.net/manual/en/function.pcntl-fork.php
Here's a good example that you might want to follow: http://php.net/manual/en/function.pcntl-fork.php#94338
Create a success method for the ajax call and have something like this:
console.log("Done");
This way you know if is complete and successful but only if you are looking at the dev tools. Unless you specify output it should not continue to run after the call has been made. Maybe you have an error in your PHP code?
EDIT: If you can't get this resolved you may want to post your PHP page as well.

Javascript Synchronization with JSON Requests

How can I make sure that a piece of code has executed completely before executing another? I am sending some ajax requests to a server and then using the returned data to generate the rest of the webpage. the things is, is that i need to have all that data in the webpage to proceed with the rest of the code as that code will affect what has been generated and, that code, runs before the json requests and all of that have finished... is there any way I can make sure this does not happen? I managed to solve it by performing the requests and then asking the user to press a button but that is a total no-sense way of doing it.
Any ideas?
Here is some code: The problem is that the second line is executed before the first (there are many calls to similar JSON functions).
$.getJSON(url, function(data){ $("#mycontent").append("..... stuff here...... create loads of dibs with class set to mydivclass"); });
...
$("div.mydivclass").hide();
Unforunately I cannot use the ajax synchronous property because: "dataType: "jsonp" requests do not support synchronous operations"
If you are using jQuery 1.5+ you can make use of deferreds to solve your issue:
function first_ajax_request() {
return jQuery.ajax(
// Your settings here
success: success_function_1
);
}
function second_ajax_request() {
return jQuery.ajax(
// Your settings here
success: success_function_2
);
}
function final_sucess_callback() {
// Do all your display work.
}
jQuery.when(first_ajax_request(),
second_ajax_request()).then(final_success_callback);
There is an excellent article on the topic that you should read up on as well by Eric Hynds. He gives some examples of exactly the kind of problem you are trying to solve.
jquery requests are asynchonize by default , so your code does not wait for the response , so you have no guarantee that code after request will execute after the response , so you can set the request synchronize by set the async property false , now the request is synchronize and you can gurantee the rest of the code will execute after the response from the server ,
like this .
$.ajax({
url: "page.php",
processData: false,
data: xmlDocument,,
async:false,
success: handleResponse
});

Categories