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)
Related
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)
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)
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!
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.
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 8 years ago.
Is it possible to retrieve variable set in onreadystatechange function from outside the function?
--edit--
Regarding execution of functions:
If its possible i would like to execute ajaxFunction() with one click
and then popup() with next click, or
somehow wait for ajax function to end and then call for alert box
In pseudocode:
function ajaxFunction(){
//creating AJAX
...
// Create a function that will receive data sent from the server
ajaxRequest.onreadystatechange = function (){
if(ajaxRequest.readyState == 4){
//success code
======>Here i want to set variable <=====
var MyVariable='MyContent';
}
}
//Retrieving page
....
}
function popup(){
ajaxFunction();
alert(MyVariable);
}
The following code assumes that the ajax-request is synchronous:
function popup(){
ajaxFunction();
alert(MyVariable);
}
But since synchronous requests are blocking the browser you should in almost all cases use asynchronous calls (If I remember correctly onreadystatechange should not be called on synchronous request but different browsers behaves differently)
What you could do is:
function ajaxFunction(callback){
//creating AJAX
...
// Create a function that will receive data sent from the server
ajaxRequest.onreadystatechange = function (){
if(ajaxRequest.readyState == 4){
//success code
callback('MyContent')
}
}
//Retrieving page
....
}
function popup() {
ajaxFunction(function(MyVariable){alert(MyVariable););
}
some's comments are correct... this has nothing to do with variable scoping, and everything to do with the fact that the inner function (the 'onreadystatechange' function) setting the value of MyVariable will not have been executed by the time that the alert() happens... so the alert will always be empty.
The inner function doesn't get executed synchronously (ie, right away), but is deferred and executed later, when the request returns, which is long after the alert() has been executed. The only solution to this is to defer the alert until after the request finishes.
But regardless of all this, the inner function can set variables outside its scope, as the other posts mention. But your problem is more about execution order than it is about variable scope.
Why not change MyVariable's scope to outside of the function?
var MyVariable;
function ajaxFunction(){
//creating AJAX
...
// Create a function that will receive data sent from the server
ajaxRequest.onreadystatechange = function (){
if(ajaxRequest.readyState == 4){
//success code
======>Here i want to set variable <=====
MyVariable='MyContent';
}
}
//Retrieving page
....
}
function popup(){
ajaxFunction();
alert(MyVariable);
}
No, because MyVariable is scoped to the function. To make it visible to popup(), it must be scoped where both the event handler function and popup() can see it, like Jenp recommends.
Pass the variable to the popup() function:
var MyVariable;
function ajaxFunction(){
//creating AJAX
...
// Create a function that will receive data sent from the server
ajaxRequest.onreadystatechange = function (){
if(ajaxRequest.readyState == 4){
//success code
======>Here i want to set variable <=====
MyVariable='MyContent';
popup(MyVariable);
}
}
//Retrieving page
....
}
function popup(x){
ajaxFunction();
alert(x);
}
This may complicate your problem so feel free to interject, but using a third party Javascript library may help ease your burden slightly (as the commenter some mentioned). Prototype and JQuery both have ways of dealing with scope, such as the bind function in Prototype. Also, you won't have to write your own Ajax request code although I commend you for digging in and seeing how it works! Prototype classes can help with scope issues like you've described. You may want to refactor in order to use asynchronous Ajax requests though so that the browser doesn't have to wait as is the case with how you've written it. The following will popup your alert message and set the variable appropriately, although I haven't tested it for errors. It shows the basic concept though.
var TestClass = Class.create();
TestClass.prototype = {
MyVariable: null,
AjaxURL: "http://yourajaxurl.com/something.asmx",
DoAjaxCall: function() {
new Ajax.Request(this.AjaxURL,
method: 'get',
onSuccess: this.AjaxCallback.bind(this),
onFailure: this.DoSomethingSmart.bind(this));
},
AjaxCallback: function(returnVal) {
this.MyVariable = returnVal.responseText; //ResponseText or whatever you need from the request...
this.Popup(this.MyVariable);
},
DoSomethingSmart: function() {
//Something smart
},
Popup: function(message) {
alert(message);
}
};
var TestClassInstance = new TestClass();
TestClassInstance.DoAjaxCall();