I need to make multiple HTTP requests to an external server via $.ajax and as far as my understanding goes, this should be asynchronous meaning that the multiple HTTP requests do not wait until the preceding request is complete before executing another one.
However, I have found that in practice, this does not hold up. I have this function:
function gethttp(i, v) {
var data = new FormData();
data.append("raw", v.raw);
$.ajax({
url: "gethttp.php?cache=" + Math.random(),
type: "POST",
data: data,
cache: false,
dataType: "json",
processData: false,
contentType: false,
success: function(data, textStatus, jqXHR) {
renderdata(i, data);
},
error: function(jqXHR, textStatus, errorThrown) {
renderdata(i, {found: "0", bibs:""});
apply(i, "danger", false);
console.log(jqXHR);
}
});
}
I then use $.each to iterate through an array requests which passes variables i and v to gethttp() for the HTTP request.
$(document).ready(function() {
$.each(requests, function(i, v) {
gethttp(i, v);
});
});
However, this process can take up to 5 minutes depending on the size of my requests array which can range in length anywhere between 5-500 items. My thought process was that this should take roughly 2 seconds because each HTTP request by itself takes that long, but by looping through it like the above, the requests are executed sequentiality and the entire process takes forever.
Do I need to go deploy this with node.js in order to get parallel processing? If so, I would really appreciate good tutorial on the subject. Can I do this with jQuery itself without resorting to node.js?
Thanks
Related
Send through ajax each element from the following array. Note: Each request must
be made once the previous has finished.
[‘This’, ‘is’, ‘a’, ‘fake, ‘array’]
I am a little confused by this question because I thought Ajax is asynchronous, meaning the script keeps sending requests to the server without waiting for the reply.
***Was downvoted so going to clarify something: It specifically states in the problem statement that the REQUEST must be made synchronously. I do realize that there are better ways of doing this via def/promises asynchronously so order remains for the result but that isn't the request.
Ajax has a async parameter you can set to false which will block until call completion.
Per documentation:
async (default: true)
Type: Boolean
By default, all requests are sent asynchronously (i.e. this is set to true by default). If you need synchronous requests, set this option to false. Cross-domain requests and dataType: "jsonp" requests do not support synchronous operation. Note that synchronous requests may temporarily lock the browser, disabling any actions while the request is active. As of jQuery 1.8, the use of async: false with jqXHR ($.Deferred) is deprecated; you must use the success/error/complete callback options instead of the corresponding methods of the jqXHR object such as jqXHR.done().
http://api.jquery.com/jquery.ajax/
Example:
$.each(["This", "is", "a", "fake", "array"], function( index, value ) {
$.ajax({
type: 'POST',
dataType: 'json',
url: '/echo/json/',
data : { json: JSON.stringify( value ) },
async: false,
success: function(data) { alert(data);}
});
});
Working fiddler example: https://jsfiddle.net/zm9bb4xk/
I was talking about JQuery Ajax.
So, first, based on documentation, Ajax has many events that run at certain times, for example:
beforeSend (Local Event)
This event, which is triggered before an Ajax request is started,
allows you to modify the XMLHttpRequest object (setting additional
headers, if need be.)
error (Local Event)
This event is only called if an error occurred with the request (you
can never have both an error and a success callback with a request).
complete (Local Event)
This event is called regardless of if the request was successful, or
not. You will always receive a complete callback, even for synchronous
requests.
success (Local Event)
This event is only called if the request was successful (no errors
from the server, no errors with the data).
More in documentation.
Second, following your example (you have to complete this with your own data and this code is not tested, maybe it has some small sintax errors), an approximation is:
// Variables
var myArray = ["This", "is", "a", "fake", "array"];
var globalIndex = 0;
// Function for Ajax Calls
function myFunction(){
$.ajax({
url: 'myURL', // Your own controller/url
type: "GET", // Or POST
dataType: "json", // Or other datatype
data: {
arrayContent: myArray[globalIndex] // arrayContent = your controller param name
},
/**
* A function to be called if the request succeeds.
*/
success: function(data) {
alert('Load was performed. Look at the console (F12 or Ctrl+Shift+I, Console tab) for more information! ');
alert(data); // Do what you want with your data, this is an example
globalIndex = globalIndex +1;
// Recursive/next call if current call is finished OK and there are elements
if(globalIndex < myArray.length){
myFunction();
}
},
/**
* A function to be called if the request fails.
*/
error: function(jqXHR, textStatus, errorThrown) {
alert('An error occurred... Look at the console (F12 or Ctrl+Shift+I, Console tab) for more information!');
alert('<p>status code: '+jqXHR.status+'</p><p>errorThrown: ' + errorThrown + '</p><p>jqXHR.responseText:</p><div>'+jqXHR.responseText + '</div>');
console.log('jqXHR:');
console.log(jqXHR);
console.log('textStatus:');
console.log(textStatus);
console.log('errorThrown:');
console.log(errorThrown);
// We don't do a recursive/next call because current call has failed
},
});
}
// First call to myFunction
myFunction();
I'm making an ajax jsonp request, but the failure error handling wont work. If the request is 404 or 500 it won't handle the error.
I've been looking around to find an answer to this, but can't find anything. There seems to be a solution with http://code.google.com/p/jquery-jsonp/, but I can't find any examples on how to use it.
function authenticate(user, pass) {
$.ajax ({
type: "POST",
url: "url",
dataType: 'jsonp',
async: false,
//json object to sent to the authentication url
data: {"u": userid, "p": pass},
success: function (data) {
//successful authentication here
console.log(data);
},
error: function(XHR, textStatus, errorThrown) {
alert("error: " + textStatus);
alert("error: " + errorThrown);
}
})
}
If you check jQuery.ajax() documentation, you can find:
error
A function to be called if the request fails (...) Note: This handler is not called for cross-domain script and cross-domain JSONP requests. This is an Ajax Event.
Because of that, you're forced to find workaround. You can specify timeout to trigger an error callback. It means that within specified time frame the request should be successfully completed. Otherwise, assume it has failed:
$.ajax({
...
timeout: 5000, // a lot of time for the request to be successfully completed
...
error: function(x, t, m) {
if(t==="timeout") {
// something went wrong (handle it)
}
}
});
Other issues in your code...
While JSONP (look here and here) can be used to overcome origin policy restriction, you can't POST using JSONP (see CORS instead) because it just doesn't work that way - it creates a element to fetch data, which has to be done via GET request. JSONP solution doesn't use XmlHttpRequest object, so it is not an AJAX request in the standard way of understanding, but the content is still accessed dynamically - no difference for the end user.
$.ajax({
url: url,
type: "GET"
dataType: "jsonp",
...
Second, you provide data incorrectly. You're pushing javascript object (created using object literals) onto the wire instead of its serialized JSON representation. Create JSON string (not manually, use e.g. JSON.stringify converter):
$.ajax({
...
data: JSON.stringify({u: userid, p: pass}),
...
Last issue, you've set async to false, while documentation says:
Cross-domain requests and dataType: "jsonp" requests do not support
synchronous operation.
Two ways to handle error,
There is no error handling for cross domain JSONP requests. Use jsonp plug-in available on Github https://github.com/jaubourg/jquery-jsonp that provides support for error handling.
jQuery ajax Timeout - Timeout after a reasonable amount of time to fire the error callback because it might have failed silently. You may not know what the actual error (or error status) was but at least you get to handle the error
I've been struggling like you for a while trying to handle errors on ajax jsonp DataType requests, however I want to share you my code, hope it helps. A basic thing is to include a timeout on the ajax request, otherwise it'll never enter the error: function
$.ajax({
url: "google.com/api/doesnotexists",
dataType: "jsonp",
timeout: 5000,
success: function (parsed_json) {
console.log(parsed_json);
},
error: function (parsedjson, textStatus, errorThrown) {
console.log("parsedJson: " + JSON.stringify(parsedjson));
$('body').append(
"parsedJson status: " + parsedjson.status + '</br>' +
"errorStatus: " + textStatus + '</br>' +
"errorThrown: " + errorThrown);
}
});
jsfiddle - Handle Errors with jquery ajax call and JSONP dataType - Error 404
I'm building a fragile JS project that uses jquery-jsonp, and came up with a dual-jsonp/ajax approach that handles errors no matter which method ends up being used.
function authenticate(user, pass) {
var ajax = ($.jsonp || $.ajax)({
'url': /* your auth url */,
'data': { /* user, pass, ... */ },
'contentType': "application/javascript",
'dataType': 'jsonp',
'callbackParameter': 'callback' // $.jsonp only; $.ajax uses 'jsonpCallback'
});
ajax.done(function (data) {
// your success events
});
ajax.fail(function (jqXHR, textStatus, errorThrown) {
// $.jsonp calls this func as function (jqXHR, textStatus)
// and $.ajax calls this func with the given signature
console.error('AJAX / JSONP ' + textStatus + ': ' +
(errorThrown || jqXHR.url));
});
}
Since both jquery-jsonp and $.ajax support the jQuery Deferred specification, we can merge the two error handlers together, handling 400 and 500-series errors, as well as lookup timeouts.
Old question but I had the same problem. Here is a solution that worked for me.
If you own the domain you shoot your request at, you can set a variable in the response and check for it on the client side.
Server Side:
SERVER_RESPONSE=true; Callback(parameter1, parameter2);
Client Side:
if(typeof SERVER_RESPONSE === 'undefined'){
console.log('No Response, maybe server is down');
}
else{
console.log('Got a server response');
}
I wanted to use long polling.
I google it and found many helpful resources, and since many, I am getting confuse which is better.
Following are three code snippets from two place.
https://gist.github.com/jasdeepkhalsa/4353139
// Long Polling (Recommened Technique - Creates An Open Connection To Server ∴ Fast)
(function poll(){
$.ajax({
url: "server",
success: function(data)
{
//Update your dashboard gauge
salesGauge.setValue(data.value);
},
dataType: "json",
complete: poll,
timeout: 30000
});
})();
// The setTimeout Technique (Not Recommended - No Queues But New AJAX Request Each Time ∴ Slow)
(function poll(){
setTimeout(function(){
$.ajax({
url: "server",
success: function(data)
{
//Update your dashboard gauge
salesGauge.setValue(data.value);
//Setup the next poll recursively
poll();
},
dataType: "json"});
}, 30000);
})();
https://github.com/panique/php-long-polling/blob/master/client/client.js
function getContent(timestamp)
{
var queryString = {'timestamp' : timestamp};
$.ajax(
{
type: 'GET',
url: 'http://127.0.0.1/php-long-polling/server/server.php',
data: queryString,
success: function(data){
// put result data into "obj"
var obj = jQuery.parseJSON(data);
// put the data_from_file into #response
$('#response').html(obj.data_from_file);
// call the function again, this time with the timestamp we just got from server.php
getContent(obj.timestamp);
}
}
);
}
My question is which code is long polling best practice?
Which one should I use?
Thanks in advance.
The first approach is better on my opinion:
If server configured for long polling with timeout more than 30000, then with first one you will have breaking request by timeout and a new request will be sent, success() function would not be called
(while complete() will be, also error could be handled in error() like this
error: function(x, t, m) {
if(t==="timeout") {
alert("got timeout");
} else {
alert(t);
}
}
).
While in the second one a new request would be sent after 30000 and so you would have unpredictable behavior on a client side (two requests can receive the same answer, so data could be duplicated).
If server configured for long polling with less than 30000, then in second approach data on a client side would not be updated in time.
If server configured for long polling with 30000, then it should not be any difference.
To summarize: in first approach situation is controllable, while in second one - not always.
I'm currently having trouble with communicating via AJAX on a Twisted HTTP Server in python. While I can send the request and have data accumulate on the server to be returned, when I try to return JSON back from the server through a simple return statement, it seems that it never calls the success function defined in Jquery AJAX, or at least its never triggered in firebug.
Snippet of Jquery Code: (Assume that its under document.ready):
function json_http_post(url, data, callback) {
$.ajax({
url: url,
type: "POST",
dataType: "jsonp",
data: {
type: data.type,
source : data.source,
trade: data.trade,
symbols: data.symbols,
time1: data.time1,
time2: data.time2,
interval: data.interval
},
success: function(data) {
callback(data);
}
});
}
The twised sever implementation is similar (or near identical) to both this and that.
The problem is that I never ever see callback(data) being called, yet I can see that python reaches my return statement with no errors and a json object to be sent back to the callback.
The javascript below accomplishes the following (this is for a node.js COMET application):
Request is made to the server and held until the server has something to
return.
Once the request returns the data is processed and another
request is immediately made within the callback function of the
success event.
If a timeout occurs (the server had nothing to return within the time frame)
another request is made within the callback function of the error event.
My concern (which I believe is valid) is that the requests are continually added to the callstack, much like a recursive function that never ends. After a while, it results in the browser eventually crashing and becoming unresponsive (at least I think this is the cause).
How can I accomplish the same thing and avoid this problem?
function GetData(){
$.ajax({
url: "admin.html",
type: "POST",
dataType: "json",
contentType: 'text/json',
data: JSON.stringify({
cmd: "getData"
}),
timeout: (60 * 1000),
success: function(data, textStatus, jqXHR){
UpdateScreen(data);
GetData();
},
error: function(jqXHR, textStatus, errorThrown){
if(textStatus == "timeout"){
GetData();
}
}
});
}
No, I'm pretty sure you are OK. The ajax event is asynchronous, so the GetData function will finish and the browser will wait for events, before it calls GetData again from the success handler.
Think of it as the GetData function just defining what to do, not actually doing it. Then it finishes executing (and clears the stack) and browser does those actions.
function GetData(limit){
limit = limit || 0;
$.ajax({
url: "admin.html",
type: "POST",
dataType: "json",
contentType: 'text/json',
data: JSON.stringify({
cmd: "getData"
}),
timeout: (60 * 1000),
success: function(data, textStatus, jqXHR){
UpdateScreen(data);
GetData();
},
error: function(jqXHR, textStatus, errorThrown){
if(textStatus === "timeout" && limit < 20){
GetData(++limit);
} else {
//throw "epic fail"
setTimeout(GetData, 0);
}
}
});
}
Just add a little timeout limit counter. if it gets too big either give up and throw an error or break the call stack by calling setTimeout which is asynchronous.
I'm wondering if your UpdateScreen(data) method is the problem. Is that a recursive function as well? People suggesting that you simply timeout the method doesn't actually fix the problem, it simply aborts the process. I would try logging something like console.log("get data success") and console.log("get data error") in your success and error callbacks respectively. If your log page is full of one message, you know where the GetData() method is continually called. It could be always timing out.
On a side note, you should change your if statement for an error to something like
if(jqxhr.responseText == "timeout"){
getData();
}
see here for explanation why: jQuery Ajax error handling, show custom exception messages