XmlHttpRequest returning state 4 too soon - javascript

I'm developing a javascript code to run on an embedded device using the ANT Galio browser.
Ideally, I'd like the code to make a get request to another server. After that get request is made, the page would not allow the user to submit another get request, until a response had been received from the previous get request.
For some reason sometimes I am receiving a readyState of 4 almost instantly. It is as though it is evaluating the previous XmlHttpRequest object and not the new one. What am I doing wrong?
<script type="text/javascript">
var fail= function (env, resp, stat) {
alert(resp);
};
var succ= function (env, resp) {
};
var canScan = true;
/* start scan */
function scan (name) {
if (canScan) {
//deactivate button
deactivateScanButtons();
//let server know
ajax = new XMLHttpRequest();
var scanUrl = 'http://19X.1XX.X.XX:8080/scan/' + name
ajax.open('GET', scanUrl, true);
ajax.onreadystatechange = function() {
if (ajax.readyState==4) {
//allow button to work again
activateScanButtons();
alert("ready state 4");
};
};
ajax.send();
//initiate scan
xrxScanInitiateScan(
'http://127.0.0.1',
"ftp.xst",
false,
succ,
fail);
}
}
function deactivateScanButtons () {
// canScan = false;
var indicator = document.getElementById('buttons');
indicator.style.visibility = "hidden";
}
function activateScanButtons () {
// canScan = true;
var indicator = document.getElementById('buttons');
indicator.style.visibility = "visible";
}
</script>

3 suggestions:
To avoid any caching on the client side, add a randomly generated number, or the current timestamp to the request querystring.
As Yoni said, initiate your XMLHttpRequest object with var keyword.
For each request, save the current timestamp within a global variable. In onreadystatechange, call activateScanButtons only if the global timestamp matches the corresponding timestamp of that given request. This way, only the latest request will be able to call activateScanButtons.

You define the ajax object in scan function without the var keyword before it. This means that it is a global object, not local. Afterwards, you have a closure - you refer to that variable in the onreadystate callback function.
I find it hard to track exactly what's going on there, but I agree with you, as you say in your question, that the callback is not using the ajax object the way you expect. You say it happens sometimes - does it happen when you make two requests almost simultaneously (double-click a button or otherwise trigger the two get requests very fast)?
I suggest that you use the var keyword before defining the ajax object. Even better, try using this in the callback function instead of referring to the ajax object by name. If it works, you have spared yourself of one closure.

Related

Define function in global scope to use in a .then() in NodeJS [duplicate]

I want to make a value on an HTML page that will be updated every 5 seconds so as to not overwhelm the server. It turns out that setTimeout() inside my function is not delaying properly, but is instead being called immediately. Can someone help me find a clue? I really don't want to give my server too much work because I have to implement a lot more AJAX.
Here's the code:
window.onload = function GetUsersNumber() {
aside = document.getElementById("users");
if (XMLHttpRequest) var x = new XMLHttpRequest();
else var x = new ActiveXObject("Microsoft.XMLHTTP");
x.open("GET", "users_count.php", true);
x.send();
x.onreadystatechange = function () {
if (x.readyState == 4) {
if (x.status == 200) aside.innerHTML = x.responseText;
setTimeout(GetUsersNumber(), 50000);
}
}
}
A function object in JavaScript is one thing. A function call is a different thing. You're using the latter, by including parentheses after the function name*, but you need the former, without parentheses. This allows setTimeout to later invoke the function itself by using the passed-in object. Assuming you do actually want 5 seconds (rather than the 50 seconds the original code was using):
setTimeout(GetUsersNumber, 5000);
*Really, any old variable that holds a function object can be invoked like that, but for convenience, defining a function also defines a variable name for it.
setTimeout takes a function as parameter. What you are doing is executing the function right away and passing is returned value of the exected function.
Pass GetUsersNumber instead of GetUsersNumber(). () will already execute the function.
setTimeout(GetUsersNumber, 50000);
On a side note:
Most of the modern browsers support XMLHttpRequest natively. So, using ActiveXObject is not required.
For older browsers, the if condition will anyways give error. Do this: if(window.XMLHttpRequest)

Parameters in callbacks in Promise [duplicate]

I want to make a value on an HTML page that will be updated every 5 seconds so as to not overwhelm the server. It turns out that setTimeout() inside my function is not delaying properly, but is instead being called immediately. Can someone help me find a clue? I really don't want to give my server too much work because I have to implement a lot more AJAX.
Here's the code:
window.onload = function GetUsersNumber() {
aside = document.getElementById("users");
if (XMLHttpRequest) var x = new XMLHttpRequest();
else var x = new ActiveXObject("Microsoft.XMLHTTP");
x.open("GET", "users_count.php", true);
x.send();
x.onreadystatechange = function () {
if (x.readyState == 4) {
if (x.status == 200) aside.innerHTML = x.responseText;
setTimeout(GetUsersNumber(), 50000);
}
}
}
A function object in JavaScript is one thing. A function call is a different thing. You're using the latter, by including parentheses after the function name*, but you need the former, without parentheses. This allows setTimeout to later invoke the function itself by using the passed-in object. Assuming you do actually want 5 seconds (rather than the 50 seconds the original code was using):
setTimeout(GetUsersNumber, 5000);
*Really, any old variable that holds a function object can be invoked like that, but for convenience, defining a function also defines a variable name for it.
setTimeout takes a function as parameter. What you are doing is executing the function right away and passing is returned value of the exected function.
Pass GetUsersNumber instead of GetUsersNumber(). () will already execute the function.
setTimeout(GetUsersNumber, 50000);
On a side note:
Most of the modern browsers support XMLHttpRequest natively. So, using ActiveXObject is not required.
For older browsers, the if condition will anyways give error. Do this: if(window.XMLHttpRequest)

chrome extension run script after ajax

I am new to Javascript, and I am creating a chrome extension where I am trying to inject some HTMLs into the existing public website,
My current code is something like this,
if (document.readyState ==='complete'){
inject_html();
}
However, on the current website, when a button is pressed, ajax is processed and new HTML DOM is loaded for the same url, so the script doesn't run.
Is there a way to listen to whenever ajax is finished processing? What is the best way in this case, can an expert help me?
This is rather hacky, but you can override any property (and thus interpose any method call) of the XMLHttpRequest prototype, as well as the function/constructor itself.
The most convenient thing to do in your case is probably to hook the XMLHttpRequest function itself, and simply add an event listener there:
var originalXHR = XMLHttpRequest;
XMLHttpRequest = function()
{
var ret = new originalXHR();
ret.addEventListener('load', function()
{
console.log('Ajax request finished!');
});
return ret;
};
The control flow here goes like this:
Call original function
Modify return value
Return modified value
This takes advantage of the fact that if in JavaScript a constructor returns a value, that value replaces the object created with new.
In action:
// Interface code
var field = document.querySelector('input');
document.querySelector('button').addEventListener('click', function()
{
var xhr = new XMLHttpRequest();
// crossorigin.me because we need a CORS proxy for most external URLs
xhr.open("GET", 'https://crossorigin.me/' + field.value);
xhr.send(null);
});
// Hooking code
var originalXHR = XMLHttpRequest;
XMLHttpRequest = function()
{
var ret = new originalXHR();
ret.addEventListener('load', function(ev)
{
// var xhr = ev.target;
console.log('Ajax request finished!');
});
return ret;
};
<!-- Demo page: -->
URL: <input type="text" value="https://google.com"><br>
<button>Load via XHR</button>
Note that this only gives you a method to detect when an XHR has finished loading, and not control over its return value. From within the function that does console.log, you do however have access to the XHR itself, via ev.target.
You could also create hooking points to modify the loaded content before it reaches the code on the page, but that would require a couple more hooks, because listeners can be added in more than one way (.onload, .onreadystatechange, .addEventListener, etc), but it would be doable if necessary.

setTimeout calls function immediately instead of after delay

I want to make a value on an HTML page that will be updated every 5 seconds so as to not overwhelm the server. It turns out that setTimeout() inside my function is not delaying properly, but is instead being called immediately. Can someone help me find a clue? I really don't want to give my server too much work because I have to implement a lot more AJAX.
Here's the code:
window.onload = function GetUsersNumber() {
aside = document.getElementById("users");
if (XMLHttpRequest) var x = new XMLHttpRequest();
else var x = new ActiveXObject("Microsoft.XMLHTTP");
x.open("GET", "users_count.php", true);
x.send();
x.onreadystatechange = function () {
if (x.readyState == 4) {
if (x.status == 200) aside.innerHTML = x.responseText;
setTimeout(GetUsersNumber(), 50000);
}
}
}
A function object in JavaScript is one thing. A function call is a different thing. You're using the latter, by including parentheses after the function name*, but you need the former, without parentheses. This allows setTimeout to later invoke the function itself by using the passed-in object. Assuming you do actually want 5 seconds (rather than the 50 seconds the original code was using):
setTimeout(GetUsersNumber, 5000);
*Really, any old variable that holds a function object can be invoked like that, but for convenience, defining a function also defines a variable name for it.
setTimeout takes a function as parameter. What you are doing is executing the function right away and passing is returned value of the exected function.
Pass GetUsersNumber instead of GetUsersNumber(). () will already execute the function.
setTimeout(GetUsersNumber, 50000);
On a side note:
Most of the modern browsers support XMLHttpRequest natively. So, using ActiveXObject is not required.
For older browsers, the if condition will anyways give error. Do this: if(window.XMLHttpRequest)

How can I take advantage of callback functions for asynchronous XMLHttpRequest?

I'm currently writing JavaScript and confusing about callback. I've found it's not kind of built-in functions though...
I'm now reading O'Relly JavaScript 5th Edition and it shows a sample code something like below:
getText = function(url, callback) // How can I use this callback?
{
var request = new XMLHttpRequest();
request.onreadystatechange = function()
{
if (request.readyState == 4 && request.status == 200)
{
callback(request.responseText); // Another callback here
}
}
request.open('GET', url);
request.send();
}
Basically, I suppose I don't understand the general idea of callback though... Could someone write a sample code to take advantage of callback above?
Callbacks are pretty simple and nifty! Because of the nature of AJAX calls, you don't block execution of your script till your request is over (it would be synchronous then). A callback is simply a method designated to handle the response once it gets back to your method.
Since javascript methods are first class objects, you can pass them around like variables.
So in your example
getText = function(url, callback) // How can I use this callback?
{
var request = new XMLHttpRequest();
request.onreadystatechange = function()
{
if (request.readyState == 4 && request.status == 200)
{
callback(request.responseText); // Another callback here
}
};
request.open('GET', url);
request.send();
}
function mycallback(data) {
alert(data);
}
getText('somephpfile.php', mycallback); //passing mycallback as a method
If you do the above, it means you pass mycallback as a method that handles your response (callback).
EDIT
While the example here doesn't illustrate the proper benefit of a callback (you could simply put the alert in the onReadyStateChange function after all!), re usability is certainly a factor.
You have to keep in mind that the important thing here is that JS methods are first class objects. This means that you can pass them around like objects and attach them to all sorts of events. When events trigger, the methods attached to those events are called.
When you do request.onreadystatechange = function(){} you're just assigning that method to be called when the appropriate event fires.
So the cool thing here is that these methods can be reused. Say you have an error handling method that pops up an alert and populates some fields in the HTML page in the case of a 404 in the AJAX request.
If you couldn't assign callbacks or pass methods as parameters, you'd have to write the error handling code over and over again, but instead all you have to do is just assign it as a callback and all your error handling will be sorted in one go.
First of all I would suggest reading up on what a callback is. Here is a start.
The big picture
Callbacks are used extensively in asynchronous programming. When you don't want to block until a (possibly) long-running operation completes, one of the ways to approach the problem is to delegate the operation to someone who will do it on the side for you. This raises the question: how will you be able to tell when the operation is complete, and how will you get its results?
One solution would be to delegate the work to someone else and take a moment off your normal work every now and then to ask "is the work I gave you done yet?". If so, get the results in some way and off you go. Problem solved.
The problem with this approach is that it doesn't make your life much easier. You are now forced to ask every little while and you will not know that the operation is done as soon as it actually is (but only the next time you remember to ask). If you forget to ask, you will never be notified.
A better solution to this is the callback: when delegating work, provide a function along with it. The code which will actually do the work then promises to call that function as soon as the work completes. You can now forget all about that stuff and be secure in the knowledge that when the work is done, your callback will be called. No sooner, and no later.
What is the callback here?
In this specific case, callback is a function that you provide to getText as a manner of allowing it to communicate with you. You are in effect saying "do this work for me, and when you are finished, here's a function for you to call to let me know".
getText in fact chooses to use this callback only when the XMLHttpRequest (XHR) is completed, and at the same time it "lets you know" it passes you the contents of the HTTP response as well (so you can act upon that information).
Callbacks and more callbacks, oh my!
But take another moment to read the code. What is the value it stores to request.onreadystatechange? What is the purpose of request.onreadystatechange?
The answer is that request.onreadystatechange is there for you to populate with a callback. In effect, XHR gives you a way to provide it with a callback, and it promises to "call you back" whenever the state of the underlying HTTP request changes.
getText is a function that builds an abstraction on top of that: It plugs its own callback (an anonymous function -- I 'll refer to that as "inner") in there and accepts another callback from you (the parameter -- I 'll refer to it as "outer"). When the inner callback (which, remember: gets called whenever the state changes) detects that the state is "completed" (the meaning of the value 4) and the HTTP response status code is 200 (which means "OK"), it calls the outer callback to let you, the user of getText, know of the result.
I hope I 'm making sense. :)
Me personally I prefer to use Event Listener over callbacks.
Using Listeners comes handy especially when You're willing to process multiple asynchronous requests at once.
The Usage is as follows (taken from https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest)
function reqListener () {
console.log(this.responseText);
}
var oReq = new XMLHttpRequest();
oReq.addEventListener("load", reqListener);
oReq.open("GET", "http://www.example.org/example.txt");
oReq.send()
XMLHttpRequest callback function and files upload with data array
function HttpPost(url, arr, cb, form){
if (form === undefined) { var data = new FormData(); }else{ var data = new FormData(form); }
if (arr !== undefined) {
for (const index in arr) {
data.append(index, arr[index]);
}
}
var hr = new XMLHttpRequest();
hr.onreadystatechange=function(){
if (hr.readyState==4 && hr.status==200){
if( typeof cb === 'function' ){ cb(hr.responseText); }
}
}
hr.upload.onprogress = function(e) {
var done = e.position || e.loaded, total = e.totalSize || e.total;
console.log('xhr.upload progress: ' + done + ' / ' + total + ' = ' + (Math.floor(done/total*1000)/10) + '%');
};
hr.open("POST",url,true);
hr.send(data);
}
// HttpPost callback
function cb_list(res){
console.log(res);
var json = JSON.parse(res);
console.log(json.id + ' ' + json.list);
// loop
for (var objindex in json.list){
console.log(json.list[objindex].id);
}
}
Sample:
var data = [];
data["cmd"] = "get-cos";
var form = $('#form')[0];
HttpPost('/api-load', data, cb_list, form);
<form id="form" method="POST" enctype="multipart/form-data">
<input type="file" name="file[]" multiple accept="image/*">
</form>
Http header content
hr.setRequestHeader("Content-Type", "application/json");
// data:
var json = {"email": "hey#mail.xx", "password": "101010"}
var data = JSON.stringify(json);
hr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
// data:
var data = "fname=Henry&lname=Ford";
What works in a proper "callback" fashion is to define a service that returns a promise like this!
$http.head("url2check").then(function () {
return true;
}, function () {
return false;
});
In the controller use the service:
<service>.<service method>.then(function (found)) {
if (found) {......
}
#jon is correct to call it Asynchronous!

Categories