Javascript text file loading delay - javascript

I'm loading a .txt file located on my server with this simple method:
function getFileFromServer(url, doneCallback)
{
console.time("getFileFromServer");
var xhr;
xhr = new XMLHttpRequest();
xhr.onreadystatechange = handleStateChange;
xhr.open("GET", url, true);
xhr.send();
function handleStateChange() {
if (xhr.readyState === 4) {
doneCallback(xhr.status == 200 ? xhr.responseText : null);
}
}
console.timeEnd("getFileFromServer");
}
I'm using it in this simple way, accordingly to this post: Reading a txt file from Server, writing it to website
function loadFile( url ) {
console.time("loadFile");
getFileFromServer(url, function(text) {
if (text === null) {
console.log("error-loading-file");
}
else {
console.timeEnd("loadFile");
doStuff(text);
}
});
As you can see I've put the console.time to keep track of the timing. Here's what the browser console answer:
getFileFromServer: 1.744ms
loadFile: 18114.871ms
I'm not a javascript expert, and the only thing I can figure out to explain the timing difference is the argument passing(value vs reference in C++).
Someone can explain me this difference in timing?

The reason why getFileFromServer finishes very fast is that there is no real processing done. The function does not wait until the request returns from the server but only registers the callback function for when it does. That means it took 1.744ms to send the request, nothing more.
The loadFile function is measuring the time between sending the request and actually getting a response. That is the difference.

Related

Getting AJAX to Work With JavaScript

Just to point out, I know how to do this with jQuery and AngularJS. The project I am currently working on requires me to use plain JavaScript.
I'm trying to get AJAX to work with just plain JavaScript. I am using Java/Spring for backend programming. Here is my JavaScript code:
/** AJAX Function */
ajaxFunction = function(url) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (xhttp.status == 200) {
var JSONResponse = JSON.parse(xhttp.responseText);
return JSONResponse;
}
}
xhttp.open('GET', url, true);
xhttp.send();
}
/** Call Function */
searchResults = function() {
var test = ajaxFunction('http://123.456.78.90:8080/my/working/url');
console.log(test);
}
/** When the page loads. */
window.onload = function() {
searchResults();
}
It's worth noting that when I go directly to the URL in my browser's address bar (example, if I go directly to the link http://123.456.78.90:8080/my/working/url), I get a JSON response in the browser.
When I hover over xhttp.status, the status is saying 0, not 200, even though I know that the link I am calling works. Is this something that you have to set in Spring's controllers? I didn't think that was the case because when I inspect this JS URL call in the Network tab, it states that the status is 200.
All in all, this response is coming back as undefined. I can't figure out why. What am I doing wrong?
An XMLHttpRequest is made asynchronously meaning that the request is fired off and the rest of the code continues to run. A callback is provided and when the asynchronous operation completes the callback function is called. The onreadystatechange function is called upon completion of an AJAX request. In your example the ajaxFunction will return immediately after the xhttp.send() line executes, so your var test won't have the JSON in it as I assume you expect.
In order to do something when an AJAX request completes you need to use a callback function. If you wanted to log the result to the console as above you could try something like the following:
var xhttp;
var handler = function() {
if(xhttp.readyState === XMLHttpRequest.DONE) {
if (xhttp.status == 200) {
var JSONResponse = JSON.parse(xhttp.responseText);
console.log(JSONResponse);
}
}
};
/** AJAX Function */
var ajaxFunction = function(url) {
xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = handler;
xhttp.open('GET', url, true);
xhttp.send();
};
/** Call Function */
var searchResults = function() {
ajaxFunction('http://123.456.78.90:8080/my/working/url');
};
/** When the page loads. */
window.onload = function() {
searchResults();
};
If you want to learn more about how XMLHttpRequest works then MDN is a much better teacher than I am :)

Javascript - updating textarea freezes browser tab

I am updating text in text area with javascript every 2 seconds, however sometimes happen that entire page freezes and you have to close the tab (other tabs in browser are working normally, this happens to all people visiting the page).
This is how my code looks like:
function ajaxSyncRequest(reqURL) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", reqURL, false);
xmlhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xmlhttp.send('server=" + server + "');
if (xmlhttp.readyState == 4) {
if (xmlhttp.status == 200){
document.getElementById(\"1\").innerHTML = xmlhttp.responseText;
if (document.getElementById('check').checked) { document.getElementById(\"1\").scrollTop = document.getElementById(\"1\").scrollHeight; }
} else {
document.getElementById(\"1\").innerHTML = "Could not connect to remote server!";\n
}
}
}
And this is the 2 seconds timer:
function timer() {
ajaxSyncRequest("ConsoleGenerator");
window.setTimeout("timer()", 2000);
}
I am getting the text with POST method to Java Servlet. It works sometimes for hours and then it freezes and browser says "Page is not reposnding..." or sometimes it works just a few minutes and then it freezes...
Can anybody help please ?
(Assuming we fix the basic syntax errors in the code.) You're happily firing off a subsequent requests without waiting for previous ones to complete. If the ajax call ever takes more than two seconds, you'll have overlapping calls. That isn't a problem in and of itself unless your backend is serializing calls or similar, but it does set up a chaotic situation.
You're also making synchronous requests by specifying false as the third argument to the POST call. There's no need to make the request synchronous, and doing so (particularly every two seconds?!) will indeed tend to lock up the UI of the browser.
I would recommend waiting for the previous request to complete before scheduling the next one, and making the requests asynchronous so the browser UI isn't locked:
// Accept callback --------------v
function ajaxSyncRequest(reqURL, callback) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", reqURL, true);
// async, not sync ----------^
xmlhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xmlhttp.send('server=" + server + "');
if (xmlhttp.readyState == 4) {
if (xmlhttp.status == 200) {
document.getElementById("1").innerHTML = xmlhttp.responseText;
if (document.getElementById('check').checked) {
document.getElementById("1").scrollTop = document.getElementById("1").scrollHeight;
}
} else {
document.getElementById("1").innerHTML = "Could not connect to remote server!\n";
}
callback(); // <== Call it
}
}
function timer() {
ajaxSyncRequest("ConsoleGenerator", function() { // Pass in a callback
setTimeout(timer, 2000);
});
}
That will wait for the ajax to complete and then schedule another update two seconds later. If you want to include the time the ajax call took in the two seconds instead, we can do some basic math:
function timer() {
var started = Date.now();
ajaxSyncRequest("ConsoleGenerator", function() { // Pass in a callback
setTimeout(timer, Max.max(0, 2000 - (Date.now() - started));
});
}
Side note: No need for the window. prefix on setTimeout (though it's harmless provided nothing's shadowed the global window), and rather than passing a string to it, just pass a function reference.

Chrome doesn't redraw page when needed

I've searched SO for similar issues (e.x. Chrome does not redraw <div> after it is hidden and Force DOM redraw/refresh on Chrome/Mac ) but none of questions gave me the solution to my problem. I am writing modem configuration panel, the webpage with ,,tabs''. On every tab there are some settings-just like configuration panel of any router.
Saving configuration (done when user clicks on Save button) takes few seconds (my embedded platform is not a speed king), so I decided to put special PLEASE WAIT window (div to be precise) which is usually hidden, but is shown when needed to calm user down :-).
Everything works fine on Firefox: after clicking save, the PLEASE WAIT div shows and then the configuration is saved using POST method. However, on Chrome 26 and Chromium 25 the div does not show until the configuration is saved. As you can see in SaveConfiguration function after executing PHP script that saves configuration the alert is shown-this is where the PLEASE WAIT div shows up on Chrome. It looks like Chrome is not redrawing page but immediately starts launching POST script. Has anyone had similar issues and now how to fix this problem?
Below are fragments of my code, I have only supplied functions that might give a clue what I'm doing. I can post more code if that helps.
function showLoadingScreen(yes)
{
if(yes)
{
document.getElementById("loadingtext").innerHTML="Please wait...";
document.getElementById("loading_overlay").style.display="block";
document.getElementById("loading_window").style.display="block";
}
else
{
document.getElementById("loading_overlay").style.display="none";
document.getElementById("loading_window").style.display="none";
}
}
function postDataSync(url, params)
{
var XMLHttpRequestObject = false;
if (window.XMLHttpRequest)
{
XMLHttpRequestObject = new XMLHttpRequest();
} else
if (window.ActiveXObject)
{
XMLHttpRequestObject = new
ActiveXObject("Microsoft.XMLHttp");
}
if(XMLHttpRequestObject)
{
XMLHttpRequestObject.open("POST", url, false);
XMLHttpRequestObject.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
XMLHttpRequestObject.send(params);
{
if (XMLHttpRequestObject.readyState == 4 &&
XMLHttpRequestObject.status == 200)
{
var result = XMLHttpRequestObject.responseText;
delete XMLHttpRequestObject;
XMLHttpRequestObject = null;
return result;
}
}
}
return '';
}
function SaveConfiguration()
{
var errors=checkForm();
if(errors!="")
{
printError("Can't save configuration because there are errors in current tab:<br><br>"+errors);
return;
}
showLoadingScreen(true);
saveTab();
var retval=postDataSync('actions/saveconf3.php','');
alert("Settings saved. The modem is now being reconfigured.");
document.location = "http://" + retval;
}
You are using ajax synchronously rather than asynchronously meaning javascript execution halts during the request. To fix make the following change:
XMLHttpRequestObject.open("POST", url, true);
You need to use a callback for the behaviour after the request is complete. Something like this:
function postDataSync(url, params, success)
{
var XMLHttpRequestObject = false;
if (window.XMLHttpRequest)
{
XMLHttpRequestObject = new XMLHttpRequest();
} else
if (window.ActiveXObject)
{
XMLHttpRequestObject = new
ActiveXObject("Microsoft.XMLHttp");
}
if(XMLHttpRequestObject)
{
XMLHttpRequestObject.open("POST", url, true);
XMLHttpRequestObject.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
XMLHttpRequestObject.send(params);
XMLHttpRequestObject.onreadystatechange = function() {
if (XMLHttpRequestObject.readyState == 4 &&
XMLHttpRequestObject.status == 200)
{
var result = XMLHttpRequestObject.responseText;
delete XMLHttpRequestObject;
XMLHttpRequestObject = null;
if (typeof success === 'function') success(result);
}
}
}
return '';
}
function SaveConfiguration()
{
var errors=checkForm();
if(errors!="")
{
printError("Can't save configuration because there are errors in current tab:<br><br>"+errors);
return;
}
showLoadingScreen(true);
saveTab();
postDataSync('actions/saveconf3.php','', saveComplete);
}
function saveComplete(result) {
showLoadingScreen(false);
alert("Settings saved. The modem is now being reconfigured.");
document.location = "http://" + result;
}
If you have heavy synchronous code (in practice, operations on hundreds or thousands of objects that are already in memory, or calculating pi to a gazillion digits) you can use setTimeout to give the browser time to catch up with any rendering tasks. You'd either need to call setTimeout for each task, or if you have a long-running task, split it up in batches first. This requires quite a bit of refactoring though, since every task needs to be represented as a function that can be passed to setTimeout.
I wouldn't use XMLHTTPRequest synchronously ever.
If setTimeout(fn, 0) does not trigger the "incremental" rendering, try a higher value, until it works. I think I needed to use a value of 100ms between jobs in some cases, for some browsers (I don't recall which).
You may need to yield to the browser even quicker if you want to achieve 60fps, or 30fps. Then you need to stay under 16ms or 33ms for each task. That gets very tight on slow hardware, such as (older types of) smartphones. Then, instead of setTimeout, you can best use requestAnimationFrame, if available.

How to load a text file in JavaScript?

I'm creating a simple WebGL project and need a way to load in models. I decided to use OBJ format so I need a way to load it in. The file is (going to be) stored on the server and my question is: how does one in JS load in a text file and scan it line by line, token by token (like with streams in C++)? I'm new to JS, hence my question. The easier way, the better.
UPDATE: I used your solution, broofa, but I'm not sure if I did it right. I load the data from a file in forEach loop you wrote but outside of it (i.e. after all your code) the object I've been filling data with is "undefined". What am I doing wrong? Here's the code:
var materialFilename;
function loadOBJModel(filename)
{
// ...
var req = new XMLHttpRequest();
req.open('GET', filename);
req.responseType = 'text';
req.onreadystatechange = function()
{
if (req.readyState == 4)
{
var lines = req.responseText.split(/\n/g);
lines.forEach(function(line)
{
readLine(line);
});
}
}
req.send();
alert(materialFilename);
// ...
}
function readLine(line)
{
// ...
else if (tokens[0] == "mtllib")
{
materialFilename = tokens[1];
}
// ...
}
You can use XMLHttpRequest to fetch the file, assuming it's coming from the same domain as your main web page. If not, and you have control over the server hosting your file, you can enable CORS without too much trouble. E.g.
To scan line-by-line, you can use split(). E.g. Something like this ...
var req = new XMLHttpRequest();
req.open('GET', '/your/url/goes/here');
req.onreadystatechange = function() {
if (req.readyState == 4) {
if (req.status == 200) {
var lines = req.responseText.split(/\n/g);
lines.forEach(function(line, i) {
// 'line' is a line of your file, 'i' is the line number (starting at 0)
});
} else {
// (something went wrong with the request)
}
}
}
req.send();
If you can't simply load the data with XHR or CORS, you could always use the JSON-P method by wrapping it with a JavaScript function and dynamically attaching the script tag to your page.
You would have a server-side script that would accept a callback parameter, and return something like callback1234(/* file data here */);.
Once you have the data, parsing should be trivial, but you will have to write your own parsing functions. Nothing exists for that out of the box.

Ajax send function wont' fire?

Whenever I run this file the code runs up to the point where the send function fires and then it only fires if I have an alert function directly behind it, if I take out the alert("sent"); out then it replies with ServerReadyyState is:1.
What could possibly be the problem? Someone please help, I've tried it on my local machine and on my personal server and got the same results. Any help is greatly appreciated.
The Code:
/**
* #author d
*/
var xhr;
function getPlants(xhr) {
try {
xhr = new XMLHttpRequest();
} catch (microsoft) {
try {
xhr = new ActiveXObject("Msxml2.XMLHTTP");
} catch (othermicrosoft) {
try {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
} catch (failed) {
xhr = false;
alert("ajax not supported");
}
}
}
xhr.open("GET", "db_interactions.php", true);
xhr.send(null);
alert("sent"); //the send function only works if this alert functions is here
if (xhr.readyState == 4) {
return xhr.responseText;
} else {
alert("Server ReadyState is:" + xhr.readyState);
xhr.abort();
//getPlants(xhr);
}
}
AJAX is asynchronus. You can't just check the ready state immediately after.
The correct design pattern is to assign a function for the AJAX call to run when the ready state changes.
xhr.onreadystatechange = function () { alert('It changed!') }
In that function, you'll want to check if the state is 4. If so, you're ready to process the output. If not, do nothing, since that function will be called a few times before the ready state is 4.
Requests take some amount of time. When adding an alert() the code is being stopped until the user clicks ok. So when you remove it the request is send and immedialty checked. Resulting in an unfinished request.
When you change your code to this:
xhr.onreadystatechange=state_change
xhr.send(null);
function state_change() {
if(xhr.readyState==4) {
return xhr.responseText;
} else {
alert("Server ReadyState is:"+xhr.readyState);
}
}
a certain function like in this case state_change gets called every time the state changes. So you can wait until the request is finished or until an errorcode comes up.

Categories