Why should we put onload before send method - javascript

I am new to JavaScript and would like to ask about about AJAX, that is, why we put xhr.onload before xhr.send() since even if I put xhr.onload after xhr.send() all works perfectly. But majority of tutorials teach you to put onload before send() without proper explanation. So, should I use
let btn = document.querySelector('button').addEventListener('click', function(){
let xhr = new XMLHttpRequest();
xhr.onload=function(){
if(this.status===200){
let div=document.querySelector('div').innerHTML=xhr.responseText;
}
}
xhr.open('GET', './mir.txt');
xhr.send();
})
Or
let btn = document.querySelector('button').addEventListener('click', function(){
let xhr = new XMLHttpRequest();
xhr.open('GET', './mir.txt');
xhr.send();
xhr.onload=function(){
if(this.status===200){
let div=document.querySelector('div').innerHTML=xhr.responseText;
}
}
})
and WHY?

Use your first version.
Logically, in the situation where the browser has the response cached, then XHR could complete instantly, and then you try to add "onload" after the response has already loaded, then nothing will happen.
In reality, even when cached, I don't think this can happen because of how the browser engine works, but from the coding point of view, it looks like it could happen. So making the pattern have onload at the top removes all suspicion that such behaviour could occur. Possibly in older browsers, when people did tend to do XHR reuests manually, that kind of thing was an actual danger?
I do know, in the scenario where you syncronously load a request, it does matter, because the thread will be blocked (as well as the whole window) during the send until it completes.

Onload is most frequently used within the element to perform a script once a website has fully loaded (including script files, images, CSS files, etc.) So Its a good approach lets load all the dependency after that we make a API call or Ajax call to update our DOM.

You don't have to use onload() before send(), your first and second example shows that already.
onload() is an event of XHR Object (a property for the load event of XHR), so it'll execute automatically when a particular event satisfies during the XHR execution. The function called when an XMLHttpRequest transaction completes successfully. So, Using onload() property you just define/tell what needs to do when load event satisfied. You don't have to define if you don't need it.
send() is a method of XHR, not an event. so you need to call it if you want it. see reference link to see more about its behavior for synchronous and asynchronous call.
Ref:
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/send
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequestEventTarget/onload

Related

Why xmlhttprequest functions open() & send() are located at the end of the function

I've been teaching myself php and xml (among other languages) and while going through the xmlhttprequest tutorial on w3schools, I noticed the open() and send() functions are located at the end of the function and not before or out of it. This is a bit puzzling because how can one get a response from the server if the request has not yet been sent? It maybe be something simple that I have missed and I apologize if that's the case but can anyone help me with my dilemma? Thanks in advance
function loadDoc() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("demo").innerHTML = this.responseText;
}
};
xhttp.open("GET", "ajax_info.txt", true);
xhttp.send();
}
The code to read the data will be in a separate function that is assigned as an event handler.
That function won't run until the response is received.
Related: How do I return the response from an asynchronous call?
It probably doesn't matter on modern browsers, but fundamentally, it's so you set up the call before sending it. In particular, so that all the handlers have been attached before asking the XHR to do something. Compare:
// Example 1
var xhr = new XMLHttpRequest();
xhr.addEventListener("load", function() {
// Got the data
});
xhr.open("GET", "http://example.com");
xhr.send();
with
// Example 2
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://example.com");
xhr.send();
xhr.addEventListener("load", function() {
// Got the data
});
Browsers are not single-threaded, though they run JavaScript code in a single main thread (plus any web workers you create). So it's possible (though extraordinarily unlikely) that with Example 2, if the resource is in the browser's cache, a separate thread handling network calls could trigger the load event between the send and addEventListener calls on the JavaScript thread, see that there were no handlers registered, and not queue a task for the event loop to call the handler. Whereas with Example 1, if it triggers the load event immediately upon send, it sees an attached handler and queues a task to call it (which runs later, when the event loop comes around to processing that task).
Here's an example of that hypothetical scenario, showing the thread interaction:
Example 1 - Highly Theoretical Scenario
JavaScript Thread Network Thread
----------------------------------------- --------------
var xhr = new XMLHttpRequest();
xhr.addEventListener("load", function() {
// Got the data
});
xhr.open("GET", "http://example.com");
xhr.send();
(Within send: Start the send, handing
off to the network thread)
1. Start a GET on `xhr`
2. It's in cache, are there any load
handlers registered on `xhr`?
3. Yes, queue a task to call the handler
(Done with current task)
(Pick up next task)
Call the handler
vs
Example 2 - Highly Theoretical Scenario
JavaScript Thread Network Thread
----------------------------------------- --------------
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://example.com");
xhr.send();
(Within send: Start the send, handing
off to the network thread)
1. Start a GET on `xhr`
2. It's in cache, are there any load
handlers registered on `xhr`?
3. No, don't queue a task to call
the handler
xhr.addEventListener("load", function() {
// Got the data
});
(Done with current task)
(Pick up next task)
(No task, do nothing)
I very much doubt any current browser would actually do that (Example 2), and I'm not aware of XHR having had a problem like this in the past. But it's theoretically possible, and there was a very similar problem, circa 2008, with setting src on an img element before hooking the load event for it. However, browsers fixed that problem, and I'd be surprised to find they were open to the Example 2 scenario above now, either, even if they or may not have been at some point in the past.
In practice, I doubt it matters. But I'd still use Example 1 if I used XMLHttpRequest (I don't, I use fetch).

Is there a way to halt an HTTP AJAX call in the browser so that another one can proceed?

I'm working on an application that makes a lot of usage of AJAX capabilities. I'm currently working on a page where there are a large number of ajax calls made to render an initial page. All these calls are routed through the same AJAX script, so they have to be made one at a time by the browser. (Yeah, it's a bit inefficient)
I've got an event that loads another page, but unfortunately it needs to make an ajax call before it can re-render the page. The result of this is that if a user clicks on that link right when the page is first loading, the browser waits for all other ajax calls before making the call to re-render the page according to the event raised by the user's click. This has been resulting in some noticeably slow load times for the page when clicking on the link to it right as the page is loading.
My question is: Is there a way to use Javascript or something to have the web browser cancel http calls to a web script so that another event can then make a call to that same script? I know that it would be nice to make each call to different scripts so they could happen concurrently, but unfortunately the application I'm working on funnels all ajax requests through a central script, and that's not going to change anytime soon.
Use the abort() method on the XMLHttpRequest object to cancel any ongoing request and return the object to a reusable state.
You could wrap it in a helper object, eg:
function HttpQueue(uri) {
var queue= [];
var xhr= new XMLHttpRequest();
xhr.onreadystatechange= function() {
if (xhr.readyState===4 && queue.length>=1) {
queue.unshift()[1](xhr);
if (queue.length>=1)
next();
}
};
this.send= function (data, callback, isurgent) {
if (isurgent && queue.length>=1) {
queue.length= 0;
xhr.abort();
}
queue.push([data, callback]);
if (queue.length==1)
next();
};
function next() {
xhr.open('POST', uri, true);
xhr.send(queue[0][0]);
}
}
var queue= new HttpQueue('/script');
queue.send('action=foo', function() {
alert('task 1 done');
}, false);
queue.send('action=bar', function() {
alert('task 2 done');
}, false);
queue.send('action=bof', function() {
alert('task 3 is urgent! tasks 1 and 2 can get knotted');
}, true);
(not tested, may work)
You can use the jQuery $.ajax method.
at which point you would specify a timeout for each call, and then set the aSync settings to false. That way you would only run one ajax request at a time.
Documentation can be found here:
http://api.jquery.com/jQuery.ajax/

Synchronous AJAX call not truly synchronous

I'm having trouble with a synchronous AJAX request.
I am creating a web application where there are many AJAX requests called in sequence which should be returned in strict order. Rather than putting every succeeding request in the readystatechange event handler of the last request, I decided to simply call them synchronously.
However, in the following code, alert() is invoked before adding the response to the DOM.
window.addEventListener("load", main, false);
function main (e) {
// Sending synchronous request
var request = new XMLHttpRequest();
request.open("GET", fileName, false);
request.overrideMimeType("text/xml");
request.send(null);
// Receiving response
var response = request.responseXML;
// Changing XML Tree to corresponding XHTML Tree
response = XMLtoXHTML(response);
//Adding response to the body
document.body.appendChild(response);
// Calling alert
alert("Hello World");
}
The response gets in fact successfully added to the DOM, but only after clicking OK on the alert message. When I do a walkthrough using Safari's Script Debugging features, the response does get added to the DOM before calling alert().
Any suggestions?
NB: I left out other requests.
I guess it actually does get added, you just don't see the changes before JS returns control back to the browser, i.e. until alert window is closed. If you cannot do an async request (which I would suggest first), you could at least make dom changes in a separate setTimeouted "thread".
It has indeed been added to the DOM but the page hasn't parsed the new element into view yet. If I had to guess it would be that since alert blocks the current running JS thread webkit tries to perform reflows during this time for efficiency.
Test case:
function foo()
{
var div = document.createElement("div");
div.innerHTML = "hi friends";
div.id = "bar";
document.body.appendChild(div);
alert(document.getElementById("bar").innerHTML);
}
Do you need the element to appear before the alert comes up? Use this in that case
setTimeout(function(){alert("Hello World");}, 1);
Or use a flow control library like Frame.js (or asnyc, flow.js, more):
Frame(function(next)){
document.body.appendChild(response);
next();
});
Frame(function(next)){
alert("Hello World");
next();
});
Frame.init();

Firefox not starting onreadystatechange function

I made some javascript code for my website, it works without problem on opera and chrome, but not on firefox.
Here is script:
function checkstate(who,row,cell) {
var zwrot="";
var mouseEvent='onmouseover="javascript:bubelon(this.id);" onmouseout="bubeloff();"';
var cellid="";
ajax=new XMLHttpRequest();
ajax.onreadystatechange=function(aEvt) {
if (ajax.readyState===4 && ajax.status===200) {
alert("im here!");
}
};
ajax.open('GET',"oth/work_prac_stan.php?usr="+who,false);
ajax.send();
}
function sprawdzstan() {
var lol="";
var table = document.getElementById("usery");
var re = /^<a\shref\=/g;
for (var i = 1, row; row = table.rows[i]; i ++) {
if (row.cells[0].innerHTML.match(re)) {
checkstate(row.cells[1].innerHTML,row,2);
} else {
checkstate(row.cells[0].innerHTML,row,1);
}
}
}
The problem is, that firefox is not running function assigned to onreadystatechange. I checked in firebug, that response from php file is correct.
Where is the problem? It works on chrome and opera, firefox just dont, no error in console, nothing.
Updated answer
According to Mozilla's docs, you don't use onreadystatechange with synchronous requests. Which kind of makes sense, since the request doesn't return until the ready state is 4 (completed), though I probably wouldn't have designed it that way.
Original answer
Not immediately seeing a smoking gun, but: Your ajax variable is not defined within the function, and so you're almost certainly overwriting it on every iteration of the loop in sprawdzstan. Whether that's a problem remains to be seen, since you're using a synchronous ajax call. In any case, add a var ajax; to checkstate to ensure that you're not falling prey to the Horror of Implicit Globals.
Off-topic: If you can possibly find a way to refactor your design to not use a synchronous ajax request, strongly recommend doing that. Synchronous requests lock up the UI of the browser (to a greater or lesser degree depending on the browser, but many — most? — completely lock up, including other unrelated tabs). It's almost always possible to refactor and use an asynchronous request instead.
Off-topic 2: You aren't using mouseEvent in your code, but if you were, you would want to get rid of those javascript: prefixes on the onmouseover and onmouseout attributes. Those attributes are not URLs, the prefix is not (there) a protocol specifier (it's a label, which you're not using).
For those who still encounter this problem...
You can use the below code. What I did is remove the function
ajax.onreadystatechange=function(aEvt) {
and transfer the alert("im here!"); after the ajax.send();
ajax=new XMLHttpRequest();
ajax.open('GET',"oth/work_prac_stan.php?usr="+who,false);
ajax.send();
alert("im here!");

Javascript asynchronous calls stepping on one another

I'm using AHAH (as outlined here http://microformats.org/wiki/rest/ahah) to make two calls to populate HTML on a page. The calls happen after the document is ready and are fired off one after another. The result, every time, is the first call gets overwritten with the last calls response. So I'll have two of the same chunks of HTML on the page instead of two unique pieces of code. Sometimes the first call doesn't even get to evaluate it's call back and thus remains empty.
Any ideas?
If you're using the exact code on that page, it's not surprising, as the example there uses a single global variable to store the XMLHttpRequest being made. So there's no way it can work for more than one simultaneous request: calling the function a second time overwrites the req with a new one, causing the req read by ahahDone to be the wrong request.
If you want to allow this you'll have to make req a local variable (by declaring it var in function ahah()), and pass it with the target to the ahahDone() function. Or just do it inline:
function Element_loadHTML(element, url) {
var req= null;
if (window.XMLHttpRequest) {
req= new XMLHttpRequest();
} else if (window.ActiveXObject) {
try {
req= new ActiveXObject('MSXML2.XMLHttpRequest');
} catch() {}
}
if (!req) {
element.innerHTML= 'Browser does not support XMLHttpRequest';
return;
}
element.innerHTML= 'Loading...';
req.onreadystatechange= function() {
if (req.readyState===4)
element.innerHTML= req.status===200? req.responseText : 'Error '+req.status;
};
req.open('GET', url);
req.send(null);
}
Element_loadHTML(document.getElementById('appdata'), 'appdata.part.html');
Element_loadHTML(document.getElementById('foo'), 'bar.part.html');
The stuff with the browser sniffing and trying to execute script tags is hopeless and broken; don't use it. It's not good practice to be loading <script> element content into the page.

Categories

Resources