i need to do several readings HTTP, and i need wait for response. But HTTP is async. Then i don't know how.
my code is:
var clientelee = Ti.Network.createHTTPClient({
// function called when the response data is available
onload : function(e) {
Ti.API.info("******* Recibido: " + this.responseText);
},
// function called when an error occurs, including a timeout
onerror : function(e) {
Ti.API.debug("****** ERROR *********"+e.error);
},
onreadystatechange: function(e){
Ti.API.info("******* STATUS *********"+e.readyState);
},
timeout : 3000 // in milliseconds
});
function LeeDatos(){
url = "http://www.hola.com/read/"+leoSerie;
// Prepare the connection.
clientelee.open("GET", url);
// Send the request.
clientelee.send();
}
for (i=0;i<NRegistros;i++){
TablaSerieTermostatos[i]=rows.field(0);
leoSerie=rows.field(0);
LeeDatos();
......
}
Any suggestion?? Thanks
On the callback could you not just pass function and when it's loaded continue with your code.
onload : function(e) {
Ti.API.info("******* Recibido: " + this.responseText);
LoadedData();
},
function LoadedData() {
// Data loaded from ASYNC Carry on...
}
or you could do it this way:
function waitForResponse( type, url, callback ) {
var client = Ti.Network.createHTTPClient({
// function called when the response data is available
onload : function(e) {
Ti.API.info("******* Recibido: " + this.responseText);
callback();
},
// function called when an error occurs, including a timeout
onerror : function(e) {
Ti.API.debug("****** ERROR *********"+e.error);
},
onreadystatechange: function(e){
Ti.API.info("******* STATUS *********"+e.readyState);
},
timeout : 3000 // in milliseconds
});
client.open(type, url);
client.send();
}
function LeeDatos(){
url = "http://www.hola.com/read/"+leoSerie;
waitForResponse( "GET", url, function() {
// Data Ready...
});
}
for (i=0;i<NRegistros;i++){
TablaSerieTermostatos[i]=rows.field(0);
leoSerie=rows.field(0);
LeeDatos();
......
}
Related
I have an upload button that when clicking calls an ajax function to upload document. Once that function runs I call another ajax function to refresh a table on screen displaying all my documents. I have been looking at this question - Wait until all jQuery Ajax requests are done?
which would seem to be what I need. However I am un-sure how to implement for my current code. I have:
$("#UploadButton").on('click', function () {
doUpload(); // My First AJAX function
refreshTable(); // My Second AJAX Function
});
My doUpload AJAX function is as below:
function doUpload() {
$.ajax({
url: 'myupload url',
type: 'POST',
data: new FormData($('#uploadForm')[0]),
processData: false,
contentType: false,
success: function () {
$.growlUI('Document Uploaded Sucessfully');
},
error: function (xhr, ajaxOptions, thrownError) {
alert(xhr.status + " " + thrownError);
}
});
}
My refreshTable ajax function then is:
function refreshTable() {
$.ajax({
url: 'url to get all files',
type: 'GET',
data: $('#searchForm').serialize(),
success: function (data) { populateTable(data); },
error: function (xhr, ajaxOptions, thrownError) { alert(xhr.status + " " + thrownError); }
});
return false;
}
If I upload a document with current solution the success function of refreshTable seems to get hit too quickly and it doesn't have the find the most recent file uploaded. I had tried to add the call to refreshTable() in the success function of my doUpload with a setTimeout of 5 seconds and sometimes this was working and refreshing the table but other times it wasn't uploading the table.
I then changed the click handler on the button to the below to attempt to have the functionality the other StackOverflow answer I linked to above has but this isn't working either
$("#UploadButton").on('click', function () {
$.when(doUpload()).done(function() {
refreshTable();
});
});
You can use callback mechanism.
function doUpload(callback) {
$.ajax({ //some parameters
success: function (data) {
//do some work here
callback();
}
);
}
Then you can call the function chain as:
doUpload(refreshTable);
EDIT : #qamyoncu answers is better than mine.
In AJAX, calls are done async. that's why you don't get what you want.
Here is a tricky solution to avoid the problem you have:
function doUpload(init) {
var res = null;
var _init = init || false;
if (!_init) {
_init = true;
$.ajax({
/// ajax call for doUpload()...
});
}
if (res == null) {
setTimeout(function(){ doUpload(_init); }, 100);
} else {
refreshTable();
}
}
I'm trying to use the code provided by Telerik to add request headers to the XHR, but I'm getting the following error.
"0x800a139e - JavaScript runtime error: InvalidStateError"
Here is the code
$(document).ready(function () {
$("#file").kendoUpload({
multiple: false,
async: {
saveUrl: "save",
},
upload: onUpload,
});
});
function onUpload(e) {
var xhr = e.XMLHttpRequest;
if (xhr) {
xhr.addEventListener("readystatechange", function (e) {
if (xhr.readyState == 1 /* OPENED */) {
xhr.setRequestHeader("X-Foo", "Bar");
}
});
}
}
It turned out that Internet Explorer fires readystatechange twice with readyState 1 and the second execution of the handler causes the error. As a workaround for the the current case you could name the executed handler and unbind it after the first execution.
function onUpload(e) {
var xhr = e.XMLHttpRequest;
if (xhr) {
xhr.addEventListener("readystatechange", function onUploadReady(e) {
if (xhr.readyState == 1 /* OPENED */) {
xhr.setRequestHeader("X-Foo", "Bar");
xhr.removeEventListener("readystatechange", onUploadReady);
}
});
}
}
The HTML code: <input id="goTOxQuestion">
The js code:
$("#goTOxQuestion").keyup(function(){
// send a XHR
})
If the input is 12345,it will send the XHR five times.In fact, I only want the XHR be executed when I have completed the input. I mean,there is no input( no keydown event )in 500 milliseconds, rather then it loses faocus.
My incomplete solution:
var isOver = false;
$("#goTOxQuestion").keyup(function(){
//...
setTimeout(function(){
if(isOver){
//send a XHR
}
},500);
})
$("#goTOxQuestion").keydown(function(){
isOver = false;
})
You can use a combination of setTimeout and clearTimeout like this:
var hTimeout;
$("#goTOxQuestion").keyup(function () {
if (hTimeout) {
clearTimeout(hTimeout);
}
hTimeout = setTimeout(function () {
// ajax code here
}, 500);
});
Demo here
Note that the order in which AJAX requests complete is not guaranteed and you will end up with "race conditions".
Regarding your comment, here is a solution from the top of my mind:
// initialize global counter
var xhrCount = 0;
// increment counter when you create an XHR
xhrCount++;
// pass the current value of this
// variable to the success function
// http://stackoverflow.com/q/1552941/87015
$.ajax("/url/", (function (myStamp) {
console.log("creating success callback #" + myStamp);
return function () {
if (myStamp === xhrCount) {
console.log("firing success handler");
} else {
console.log("suppressing success handler");
}
}
})(xhrCount));
Use setTimeout then:
$("#goTOxQuestion").keyup(function(){
setTimeout(function(){
// send a XHR
}, 1000);
})
The change event seems like a good fit for your needs :
$("#goTOxQuestion").change(function(){
// send a XHR
})
It will be triggered when the input looses focus and the input value was actually modified.
$(document).on('blur',"#goTOxQuestion",function(){
// send a XHR
});
var refreshId_hxlatestposts = setInterval(function() {
var el = $("#hxlatestposts");
var req = $.get("example.php");
el.fadeOut('slow', function () {
req.done(function( data ){
el.html(data).fadeIn('slow');
});
});
}, 60000);
This is what i use to refresh a div every minute, sometimes it gets hung up when the site it is getting the feed from is down or something. I'd like to some how have a timeout so if it cannot load the php file in X seconds then return 'Fail to load'.
jQuery documentation (.ajaxSetup()) suggests using .ajaxSetup() to set the value for timeout, instead of using it in individual requests.
You can use request.fail() to register a function in case of a failed request.
$.ajaxSetup({
timeout: 5000
});
var refreshId_hxlatestposts = setInterval(function() {
var el = $("#hxlatestposts");
var req = $.get("example.php");
el.fadeOut('slow', function() {
req.done(function(data) {
el.html(data).fadeIn('slow');
});
req.fail(function(jqXHR, textStatus) {
el.html('Fail to load').fadeIn('slow');
});
});
}, 60000);
Nice use of deferred objects.
If you replace $.get with $.ajax, you can add a timeout.
var req = $.ajax({
url: "example.php",
type: "GET",
timeout: 5000 // 5 seconds
});
and then add a fail handler
req.done(function(){...}).fail(function(){
alert("failed to load");
});
You'll want to check the status of the incoming response to ensure that the service returned a 200 Ok status. This is more reliable than just waiting for a timeout-- you will know if it's good data or not an can decide to retry by putting your timeout in the complete functions.
$.ajax({
//...
success: function(data, textStatus, xhr) {
console.log(xhr.status);
//handle status codes etc.
// then set your timeout
},
complete: function(xhr, textStatus) {
console.log(xhr.status);
//handle status codes etc.
// then set your timeout
},
// OR
fail: function( xhr, textStatus ){
//retry code or timeout
}
});
jQuery's $.get is just a shorthand for $.ajax, which is used when more flexibility is required (in your case, yes)
Replace $.get("example.php"); with:
$.ajax({
type: "GET",
url: "example.php",
timeout: X*1000,
}).done(function(data) {
el.fadeOut('slow', function () {
el.html(data).fadeIn('slow');
});
}, 60000);
});
where X is number of seconds you would want it to wait (timeout)
I am confuse about the xhr return event, as I can tell, there are not so much different between onreadystatechange --> readyState == 4 and onload, is it true?
var xhr = new XMLHttpRequest();
xhr.open("Get", url, false);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4)
{
/* do some thing*/
}
};
xhr.send(null);
or
xhr.onload = function() { /* do something */ }
This is almost always true. One significant difference, however, is that the onreadystatechange event handler also gets triggered with readyState==4 in the cases where the onerror handler is usually triggered (typically a network connectivity issue). It gets a status of 0 in this case. I've verified this happens on the latest Chrome, Firefox and IE.
So if you are using onerror and are targeting modern browsers, you should not use onreadystatechange but should use onload instead, which seems to be guaranteed to only be called when the HTTP request has successfully completed (with a real response and status code). Otherwise you may end up getting two event handlers triggered in case of errors (which is how I empirically found out about this special case.)
Here is a link to a Plunker test program I wrote that lets you test different URLs and see the actual sequence of events and readyState values as seen by the JavaScript app in different cases. The JS code is also listed below:
var xhr;
function test(url) {
xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", function() { log(xhr, "readystatechange") });
xhr.addEventListener("loadstart", function(ev) { log(xhr, "loadstart", ev.loaded + " of " + ev.total) });
xhr.addEventListener("progress", function(ev) { log(xhr, "progress", ev.loaded + " of " + ev.total) });
xhr.addEventListener("abort", function() { log(xhr, "abort") });
xhr.addEventListener("error", function() { log(xhr, "error") });
xhr.addEventListener("load", function() { log(xhr, "load") });
xhr.addEventListener("timeout", function(ev) { log(xhr, "timeout", ev.loaded + " of " + ev.total) });
xhr.addEventListener("loadend", function(ev) { log(xhr, "loadend", ev.loaded + " of " + ev.total) });
xhr.open("GET", url);
xhr.send();
}
function clearLog() {
document.getElementById('log').innerHTML = '';
}
function logText(msg) {
document.getElementById('log').innerHTML += msg + "<br/>";
}
function log(xhr, evType, info) {
var evInfo = evType;
if (info)
evInfo += " - " + info ;
evInfo += " - readyState: " + xhr.readyState + ", status: " + xhr.status;
logText(evInfo);
}
function selected(radio) {
document.getElementById('url').value = radio.value;
}
function testUrl() {
clearLog();
var url = document.getElementById('url').value;
if (!url)
logText("Please select or type a URL");
else {
logText("++ Testing URL: " + url);
test(url);
}
}
function abort() {
xhr.abort();
}
It should be the same thing. onload was added in XMLHttpRequest 2 whereas onreadystatechange has been around since the original spec.
No, they are not the same. If you encounter a network error or abort the operation, onload will not be called. Actually, the closest event to readyState === 4 would be loadend.
The flow looks like this:
onreadystatechange
readyState === 4
⇓
onload / onerror / onabort
⇓
onloadend
in simple code here how they are handle the error
xhr.onload = function() {
// same or allowed cross origin
if (this.status == 200) {
}
else {} // error http status not 200
};
xhr.onerror = function() {
//error: cross origin, bad connection
};
VS
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (this.status == 200) {
}
else {} // error: cross origin, http status not 200, bad connection
}
};