Javascript block on AJAX load - javascript

I am looking for a way to make an AJAX load request in javascript, but have the javascript code pause execution while waiting for the AJAX load to complete. In other words, I am trying to do a synchronous AJAX load request (I know the 'A' in AJAX stands for asynchronous. I'm just hoping maybe the name isn't exactly right.) . What I have is
$('#my_id').load("my_page.pl?my_param=p1&my_other_param=p2");
//Please wait here
//Now do stuff after load is complete.
The reason I want the request to be synchronous is because it creates an HTML table, and then the javascript which follows parses the table.

jQuery's 'load()' method takes a callback. Callbacks are generally how async code handles the "waiting" feature you want.
$("#my_id").load("my_page.pl?my_param=p1&my_other_param=p2", function (response) {
// do this stuff, which will run after the request is complete
});

That looks like jquery... I can't be sure because I don't know jquery at all but if so you might get better answers tagging it as such.
I can tell you that javascript has it's own method for synchronous OR asynchronous calls. This is what I use:
var xmlhttp;
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest();
}
else {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
// Use the activeX object for old IE
xmlhttp.open("GET","http://some.internet.address/woot?foo=bar", false);
// The third argument in the open function determines the asynchronous nature,
//it was set to false, so the code will halt at the send() point while the request is executed.
xmlhttp.send();
// Now, if the call succeeded...
if (xmlhttp.status==200) {
response = eval('('+xmlhttp.responseText+')');
// ...save the results to an object named response...
}
else {
// ...Otherwise do some other stuff
errorFunction(xmlhttp.status);
}
Lots of good info is also available here -
http://www.w3schools.com/ajax/ajax_xmlhttprequest_send.asp

Related

Trouble with callback function in asynchronous 'Post'

I am new to javascript, and I am having an issue with a line of code executing before the previous line has finished. From what I understand, I need to create a callback function which will make the last line wait for the previous line to finish. My program takes user input and uses an asynchronous 'post' to send it to a website, and then a message is returned. My original problem occurred when I had the two following lines of code together:
req.send(JSON.stringify(payload))
event.preventDefault();
preventDefault() is not waiting for the send() function to finish. I have tried implementing a callback function, but I am having problems with that as well.
function sendReq(callback){
req.send(JSON.stringify(payload), function(){
callback();
});
}
sendReq(function(){
event.preventDefault();
});
Any suggestions would be much appreciated. Here is my entire code in case that helps.
var apiKey = "appid=fa7d80c48643dfadde2cced1b1be6ca1";
document.addEventListener('DOMContentLoaded', bindButtons);
function bindButtons(){
document.getElementById('dataSubmit').addEventListener('click', function(event){
var req = new XMLHttpRequest();
var payload = {longUrl:null};
payload.longUrl = document.getElementById('inputData').value;
req.open('POST', 'http://httpbin.org/post&' + apiKey, true);
req.setRequestHeader('Content-Type', 'application/json');
var response = JSON.parse(req.responseText);
req.addEventListener('load',function(){
if(req.status >= 200 && req.status < 400){
document.getElementById('outputData').textContent = response.longUrl;
}
else
console.log("Error in network request");
});
function sendReq(callback){
req.send(JSON.stringify(payload), function(){
callback();
});
}
sendReq(function(){
event.preventDefault();
});
});
}
You misunderstand how callbacks work. Check out this article from recurial.com: Understanding callback functions in Javascript
You can't "wait" in JavaScript[*] - due to something called "Run-to-completion" semantics: your code always runs in response to an event (such as "DOMContentLoaded", "click", or XHR's "load") and no more events - and no other event handlers - will be processed until your currently running code finishes (typically by return-ing from the outermost function -- the event handler).
Long-running JS code makes the web page freeze, which is why you were asked to write an asynchronous request in the first place -- synchronous XHR will cause the page to freeze while your code waits for the response from the server.
To avoid the freezes and still get the job done, you can structure your code as a series of callbacks: after you start an asynchronous request you return from the current function and let the system call you back when it has the response. The only moment when you can use the response is in the callback, by the very definition of the callback.
In your case, the callback that indicates that the response is available is the load handler. That's where you should move your var response = JSON.parse(req.responseText); line.
PS. preventDefault() is completely unrelated to your situation, it can't be used to "wait for the send() function to finish"; it's used in cases when you handle an event (such as onsubmit for a <form>) and you want to prevent something that the browser does by default when this event fires (in the <form> example -- well -- submitting the form).
PPS. After you figure out the basics and start writing code that has more than 2 callbacks in a row, look up "promises".
PPPS. [*] Ignore this remark, I added it just to be precise, as it will only confuse you at this stage: You can't "wait" in JavaScript unless you're writing a "generator" and/or using the currently unavailable async/await).

http request in while loop in JavaScript

I am trying to send a xmlHttpRequest in a while loop and want to do something with the response in the same while loop. Since the requests are asynchronous, how can I achieve it? I need to execute everything serially
while(i < n){
response = self.sendHttpRequest(params);
//do something with the response
}
Any help would be appreciated.
Even If I use a callback, how can I get back to same while loop after executing the callback?
There are two ways I can think of:
1. Add a polling loop after the get call that waits until the response.readyState is set and then process the response:
while(i < n){
response = self.sendHttpRequest(params);
while( response.readyState != 4 ){
// polling wait
}
//do something with the response
}
This option is not really recommended since it stops the flow of the code and you can get stop in the loop if the readyState never changes (not likely, but possible with errors).
2. You can encapsulate the request in a function that will be called recursively when the last response handling finishes:
var i = 0;
function handle( response ){
//handle response
i++;
if( i < n ) sendRequest();
}
function sendRequest(){
// Your request setup code
response.onreadystatechange = handle;
response = self.sendHttpRequest(params);
}
The second method is preferred in my opinion, as it maintains the asynchronicity of the html request call, and doesn't stop the flow of the code, however it does "break" the loop structure. The first method keeps the loop structure, but is not very good coding practice.
Are you using any ajax library or plain js. If you are not using any library ,you can pass third argument to open method false.like below
var xmlHttp=new xmlHttpRequest();
xmlHttp.open({YOUR_METHOD},{YOUR_PATH},false);
Passing false to open method makes synchronous call .so you can handle the return in same loop.

Understand Ajax XMLHttpRequest in details

I am new to Ajax, and to make things worse, also a Javascript noob, and I have posted the bellow code of a chat script, to retrieve text from db, in real time, and the code is working, but I need to understand what certain requests are all about.
<script>
function retrieve(){
var xmlhttp;
if(window.XMLHttpRequest){
xmlhttp = new XMLHttpRequest(); }
else if(window.ActiveXObject) {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); }
else {
alert('Please update your browser to start chatting');
}
Simply, I understand the above is (I created it) just a function with global variable declared to be assigned whether XMLHttpRequest/ActiveXObject Object is declared depending if browser is IE6,7 and others if not throw in alert...
xmlhttp.onreadystatechange = function(){
if(xmlhttp.readyState == 4 && xmlhttp.status == 200){
document.getElementById("canvas").innerHTML = xmlhttp.responseText;
}
}
Similarly, the above I assume takes the onreadystatechange property of the Ajax API and checks for it's state, readyState & status which, if only they match 4 and 200 means, Ajax is working as wanted
t = setTimeout("retrieve()", 2000);
I know the setTimeout() is a bit like setInterval() function, which runs the function inside it, every 2 seconds, to check for new messages.
xmlhttp.open("GET", "getajax.php", true);
xmlhttp.send();
Now, the problem is with the above, I can almost understand that the .open method is supposed to get data from getajax.php even though, I have no idea of what true means in this instance, but as far as the xmlhttp.send(); I have absolutely no clue,
So, All I need is for you to explain to me what I have missed during my illaboration, and
what the last queries mean, just in brief.
}
retrieve();
</script>
<div id="canvas"></div>
xmlhttp.open("GET", "getajax.php", true);
xmlhttp.send();
true is what tells the request to be performed A -synchronously, which is the A in AJAX. Then finally .send() actually send the request.
Asynchronous requests are non-blocking meaning that the rest of your code wont wait for them to finish and return before continuing. That is why you sent event handlers before starting the request via xmlhttp.onreadystatechange. That way once the request is complete you have already told your script what to do with the returned information.
Hope this helps.
Edit Additionally I recommend using some sort of framework or library for javascript like jQuery. While it is good to learn some of the javascript core, something like jQuery will make your life much easier.
Simply, I understand the above is (I created it) just a function with global variable declared to be assigned
xmlhttp isn't a global. It's a local variable in the global function retrieve.
Similarly, the above I assume takes the onreadystatechange property of the Ajax API and checks for it's state
onreadystatechange is a property that accepts a function. That function is run when the value of readyState changes. That function is usually used to check the status of the request.
I know the setTimeout() is a bit like setInterval() function, which runs the function inside it, every 2 seconds, to check for new messages.
setTimeout is like setInterval in a sense that it runs a function at a later time. Unlike setInterval, it only runs the code once. Also, that's not the proper way of running a timer. Here's a post that explains how to properly use timers.
the .open method is supposed to get data from getajax.php even though, I have no idea of what true means in this instance, but as far as the xmlhttp.send(); I have absolutely no clue
The open builds your request by accepting:
The type of request (GET/POST)
The url where you want the request sent
The third argument determines if the request is asynchronous or not.
If set to false, this makes the request synchronous. The browser will freeze and wait for the response.
If true, the request us asynchronous. The browser will not freeze in waiting.
The default value is true, so you can omit it.
send is the actual function that ultimately sends the request to the server.
For further reading, I suggest you read MDN's section regarding AJAX.

what is the right way to manage multiple ajax requests?

We've all seen some examples in AJAX tutorials where some data is sent. They all (more or less) look like:
var http = createRequestObject(); // shared between printResult() and doAjax()
function createRequestObject() { /* if FF/Safari/Chrome/IE ... */ ... }
function printResult()
{
if (http.readyState == 4) { ... }
}
function doAjax() {
var request = 'SomeURL';
http.open('post', request);
http.onreadystatechange = printResult;
data = ...; // fill in the data
http.send(data);
}
// trigger doAjax() from HTML code, by pressing some button
Here is the scenario I don't understand completely: what if the button is being pressed several times very fast? Should doAjax() somehow re-initialize the http object? And if if the object is re-initialized, what happens with the requests that are being already on air?
PS: to moderator: this question is probably more community-wiki related. As stated here (https://meta.stackexchange.com/questions/67581/community-wiki-checkbox-missing-in-action) - if I've got it right - please mark this question appropriately.
Since AJAX has asynchronus nature, with each button click you would raise async event that would GET/POST some data FROM/TO server. You provide one callback, so it would be triggered as many times as server finishes processing data.
It is normal behaviour by default, you should not reinitialize of http object. If you want to present multiple send operation you have to do that manually (e.g. disabling button as first call being made).
I also suggest to use jQuery $.ajax because it incapsulate many of these details.
Sure that numerous libraries exist nowadays that perform a decent job and should be used in production environment. However, my question was about the under-the-hood details. So here I've found the lamda-calculus-like way to have dedicated request objects per request. Those object will obviously be passed to the callback function which is called when response arrives etc:
function printResult(http) {
if (http.readyState == 4) { ... }
...
}
function doAjax() {
var http = createRequestObject();
var request = 'SomeURL';
http.open('get', request);
http.onreadystatechange = function() { printResult(http); };
http.send(null);
return false;
}
Successfully tested under Chrome and IE9.
I've used a per-page request queue to deal with this scenario (to suppress duplicate requests and to ensure the sequential order of requests), but there may be a more standardized solution.
Since this is not provided by default, you would need to implement it in JavaScript within your page (or a linked script). Instead of starting an Ajax request, clicking a button would add a request to a queue. If the queue is empty, execute the Ajax request, with a callback that removes the queued entry and executes the next (if any).
See also: How to implement an ajax request queue using jQuery

Two xmlHttpRequests in a single page

I'm fairly new to ajax but am trying to implement two simple calls to dynamically changes two separate divs on a page using javascript. I have no problems using one call at a time, but when I use two it seems like the second xmlhttprequest takes over the first and writes into both divs.
I've read and tried using the fixes listed on these two other posts both neither seem to work in my case:
Sending two Ajax requests to two different PHP scripts from single javascript function
Using two xmlhttprequest calls on a page
And here is my relevant code:
function request_handler(url, params, changed_div) {
if(window.XMLHttpRequest) {
try {
req = new XMLHttpRequest();
}catch(e) {
req = false;
}
}else if(window.ActiveXObject) {
try {
req = new ActiveXObject("Msxml2.XMLHTTP");
}catch(e) {
try {
req = new ActiveXObject("Microsoft.XMLHTTP");
}catch(e){
req = false;
}
}
}
if(req) {
req.onreadystatechange = function(){
if (req.readyState == 4 && req.status == 200){
document.getElementById(changed_div).innerHTML = req.responseText);
}
}
req.open("POST", url, true);
req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
req.send(params)
return true;
}
return false;
}
Here is the basic format of each request using the function above:
request_handler("sample.php", parameters , "sample_div");
Apologies if I'm passing something simple up here, I just can't seem to get it to work.
This question
Using two xmlhttprequest calls on a page
does answer your question.
In your request_handler function, you're using a global variable req that gets overwritten every time you call that function.
If you change it to start:
function request_handler(url, params, changed_div) {
var req;
// Rest of your function
}
you should find that it works. In this case req has a local scope and so is not overwritten when you call request_handler for the second time.
Can I also suggest that you strongly consider using the likes of jQuery, Prototype or Dojo, if you're planning on writing Ajax scripts? Writing scripts that work cross-browsers is hard to do well and these frameworks do a lot of the legwork for you.
Your req is a global variable as it is defined without the var keyword, keep that in mind.
What I think happens is that the second call overwrites the first one. This is because of the (default) asynchronous nature of the XMLHTTPRequest. Your first function call will end, but the fetching of the page is still going. The second function call then overwrites the previous request.
This however does not explain why both div get filled with the result of the second call. I must say I'm a bit lost on that one.
This is a pretty common problem, especially if you don't want to take additional measures to block further calls until the first has finished loading. Its a bigger subject that I can cover in a post but there are several examples on the web of an "Ajax Queue" that effectively manages the order of requests received.
jQuery has a plugin for managing queues and I'm certain that most other JavaScript frameworks such as Prototype and MooTools will as well. If you're wanting to stick with raw JavaScript I would take a look at this web page:
http://www.cmarshall.net/MySoftware/ajax/index.html
He implements a queue very effectively and has an excellent example of its use.

Categories

Resources