Chrome AJAX on page-load causes "busy cursor" to remain - javascript

In Google Chrome, AJAX called within $(function(){....}); seems to keep the page loading.
I have a site with a few pages with tabs. Because I'm using cheap godaddy hosting, I want the page to load as fast as possible. I thus want to load a page on 1 tab and then in the background use AJAX to load the other tabs. When I run AJAX from
$(function(){
/*AJAX CODE HERE */
});
The cursor shows the page as loading for a long time (http://jsfiddle.net/mazlix/7fDYE/9/)
I have figured out a way (in chrome atleast) to somewhat fix that using setTimeout(); (http://jsfiddle.net/mazlix/7fDYE/8/), but this only works if you correctly predict when the window finishes fully loading and obviously makes it take longer to load. I want a way to load content via AJAX immediately after the page loads, so no "busy-cursor" is displayed while waiting for the returned AJAX.

Google Chrome shows Loading Indicator as long as there are no new queries to servers. While the loading indicator is shown, all new requests are causing Chrome to extend the time the indicator is shown. Furthermore, when esc is pressed while the indicator is shown, all requests are aborted! These include AJAX requests and even Flash requests! Take a look at this question: i thought it was because of Youtube, but it turned to be Chrome's usual behavior.
The only way to avoid "extending" the time Loading indicator is shown, is making the requests after the loading indicator is hidden: i.e. when all queries to server are completed. JQuery's documentation on .load() says:
The load event is sent to an element when it and all sub-elements have been completely loaded. This event can be sent to any element associated with a URL: images, scripts, frames, iframes, and the window object.
So, if you're sure that there are only images, scripts and frames on your page, window.load() will be fired just when you need it. Adding setTimeout() to it will work as you like. Here is an example: http://jsfiddle.net/7fDYE/22/
If there are other requests being made before your request, you should wait for them to be completed! For example, you know that besides the images/scripts etc. you have 3 more AJAX requests before the page loads. You can have something like this:
var loaded=0,needsToBeLoaded=4; //3 AJAX + window
function onLoad(){
loaded++;
if(loaded==needsToBeLoaded){
//do the AJAX request
}
}
window.load(onLoad);
// add onLoad() to all 3 AJAX request handlers
I'm not sure what you can do with Flash requests...

Update
This solution will not work for Chrome. It stops the loading indicator only when all requests made before window load have completed. The only solution appears to be to get it to make the request after window load, but as far as I know, this is only possible with setTimeout, which isn't great.
Update
To get around the pointer issue in Chrome, you could set the cursor style as shown in this fiddle. It's a bit hacky and it doesn't address the issue of the loading indicator at the top of the tab.
The loading indicator will be present in browsers until the page has loaded (window's load event). In $(function(){someCode();});, someCode is executed when the DOM load event is triggered (when all content has been parsed and inserted into the DOM, before page load). The execution of JavaScript at this point blocks the window's load event from firing, and so prevents the loading indicator from stopping. Note that image loading also blocks the window's load event.
Instead, you could try $(window).load(function(){someCode();});. In this example, someCode is executed when the window's load event is triggered. This is at the point where the browser's loading indicator stops.
So, instead of:
$(function(){
/*AJAX CODE HERE */
});
Try:
$(window).load(function(){
/*AJAX CODE HERE */
});
Note that this may cause your JavaScript to begin execution later, which may not be desirable.

There is a super simple, fool proof solution to this:
Wrap your function in a setTimeout call, and use an interval of 0. This will queue the function to be called immediately, but Chrome will no longer wait for it to load before considering the page 'complete'. You do NOT need to make any guesses about when the page will be complete, just make sure you're calling setTimeout inside the jquery Ready handler, like so:
$(window).load(function() {
setTimeout(function() {
$("#result").html(ajax_load);
$.post("/echo/json/", {json: json1, delay: 10000}, show_json, "json");
}, 0);
});

According to JQuery docs, no javascript should be run till ready for example
$(document).ready(function() {someCode();});
with that in mind i changed your jsFiddle (it takes some time to load but it works)
Edit: hadnt forked jsfiddle ><

I'm not sure I agree that this is a problem. I'd say this is a desirable behavior from chrome as it indicates that it's in fact not finished loading. I would say that Firefox is actually incorrect about not indicating that it's still waiting for a script callback to finish.
This could be a matter of personal taste (I like the browser to indicate that it's waiting/working, even if it makes my browser seem slow), in which case succeeding in "fixing" this "problem", will make the browser not behave in the way the user is used to. In web development you really should not try to force the browser to behave in a specific way that is not essential to how the webapp works, because you're likely to end up enforcing a look-and-feel from one os you're used to into another os with a different feel, making it feel more foreign to the users of another os (even if it makes the site feel more native to you).
The busy cursor is not a problem anyway, because elements already loaded, are still responsive.

Looks like this is a Chrome issue and they are not fixing it:
https://bugs.chromium.org/p/chromium/issues/detail?id=26723

Related

Why does `alert("2nd");` execute before `window.history.back();`?

When I ran the following two JavaScript commands...
> window.history.back(); alert("2nd");
...I was expecting the window to go to the previous page, and then display the alert. What happens is "2nd" actually pops up first, and then the window goes back. If I reverse them like this...
> alert("2nd"); window.history.back();
...the commands still execute in the same order. What don't I understand about JavaScript control flow? How would I get window.history.back(); to run first?
Well, it makes sense that the alert is not displayed after the other page has loaded. The script is part of the loaded page, so if that would work, it would mean you could inject javascript in the previous page, which is of course undesirable.
So as I see it, there are 3 possibilities:
The back function is blocking and works immediately, navigating to a previous page, and terminate the running script. This obviously isn't happening, otherwise you wouldn't get the alert at all.
The back function works immediately, but the script is only terminated when the browser has enough information to start loading the other document. This doesn't seem to be the case. If it were, the browser would probably load the document in the background while the alert is open, but that doesn't happen.
The back function just signals the browser to go back, and the script keeps running until it's idle before that request is actually fulfilled. This seems to be the case. Navigation only starts when the alert is closed and the script ends. (At least in Chrome).
Anyway, if you want this to work, you'll have to call alert from the page you are navigating to.
Control has to be given back to the browser before back is actually executed. It just tells the page when you get a chance, go back.
Once control is return the browser unloading hooks are called (onbeforeunload, onunload, browser specific events).

Chrome extension: page loads faster than extension code

I am working on the extension that needs to update page texts after page is loaded. I use window.onload in "content_script".
As I need to test my changes a lot I decided to create a little page with a few paragraphs of text and put it in my web server. But when this page loads - extension's window.onload doesn't trigger, wheres on any other internet page it works properly.
I started investigation and found out, that this is because of the page loading speed. So basically page loads faster than extension code.
It was verified by adding background image on the body linked to the external site. Like this:
body
{
background: url(http://colourunity.com/img/2013/07/autumn-wallpaper-computer-14172-hd-widescreen-wallpapers.jpg) no-repeat;
}
So the page's loading speed slows down and extension has enough time to load in and window.onload triggers.
Of course I don't worry about extension work, because it is too rare case when page loads that fast.
But still - is there anyway to bypass this?
Thanks.
The window object of your content script is not the same as the one of your page. From the content script documentation:
It's worth noting what happens with JavaScript objects that are shared by the page and the extension - for example, the window.onload event. Each isolated world sees its own version of the object.
Therefore listening for this event in your content script won't work as you intent, since it's not the one you want.
It doesn't matter anyway: you can specify at which point your script is executed via the run_at option. For example, if you choose to run it at document_idle, then you're guaranteed it's executed after the window.onload event of your page.
In other words, you can simply stop using the window.onload event, and directly run the code you need.

Is there a way to determine if all local JavaScript assets are loaded?

At first this might seem an odd question, but here's my problem. I'm developing a website that on window.load calculates the div positions as it has some dynamic scroll event highlighting (DOM Ready is the wrong choice for this as images and content isn't loaded yet and the calculate div positions are incorrect when the page has fully rendered.) The local assets run perfectly and are optimised for performance, but my problem is that the client wants social media embeds, for instance a twitter follow and facebook like button. Twitter seems to render pretty quickly, but Facebook takes so long and you can literally lag for about 20-30 seconds before the window.load event is ready, which means my navigation then lags and doesn't work properly. I don't know if it's even possible, but is there a way to determine when all local JavaScript files are loaded (these are included before the closing body tag).
Probably. All JavaScript in a page is executed in the order in which the browser encounters it. So when you add a <script> element as the last element inside the <body> element (i.e. at the bottom of the page), this code will run after all other script code has been executed. Also, at that time, the DOM will be finished (no further HTML to process) except for things that callbacks still might do (timers, onload-handlers).
So what you can try is to put a <script> element between your code and the code from Facebook. But that means your DOM won't be ready.
A better solution is probably to start loading the Facebook code in the background inside of onload. That means all the rest of the page is there and Facebook can take its time.

universal loading animation for location.href changes

A customer's site we show in an iFrame is extremely slow (~7s).
We can only provide a JavaScript file the customer will include, but he won't do more than that.
Is it possible for me to hook to all events (forms submitted, links clicked) and display a nice loading animation until the page is fully loaded?
Or can I universally ajax-ify his site?
Once your page is unloaded and the other page starts loading, the code from the original page is no longer available or running so it can't be doing anything and the content from the original page has been cleared so it can't be showing anything.
In that same situation, the next page is in the process of being loaded and it's code is not yet running.
Thus, you cannot use normal page javascript to run something throughout the loading of a new page. To do something like this, you would either have to use frames with progress showing in one frame while content loading in another frame or perhaps use a browser plug-in.
You can know when a page is being unloaded with the beforeunload event, but as soon as the next page starts to load, any code assigned to this will no longer be running and the current document will have been cleared.

does a chrome extension content script get stopped if it takes too long to finish?

I have a content script running on every page. It updates the html of the page, which seems to take more time on longer pages (the script walks the DOM a lot of times). On longer pages the script could take up to 10-20 seconds to finish, and it seems that when it takes too long chrome stops the script, because on these pages I see only a part of the page changed.
The weird part is that when I add several alerts somewhere in the code, dividing the runtime to several parts, the script runs perfectly fine and changes the entire page. However when the alert is removed, the script is again stopped prematurely, and only a part of the page gets changed.
My only conclusion is that chrome stops scripts that run too long, so my question is - is that true? And if so - what can be done about it? (besides using annoying pop-up alerts)
I have another theory, the script stops because somehow there is a conflict when simultaneous commands try to change the DOM. Does this make more sense?
More details about the architecture: The background page gets a message from the content script. This message includes a callback function (the function that actually changes the HTML). This function is then called from the background page several times, relative to the length of the page. If I insert an alert inside the callback function, every call is run without problems. If however I remove it, only the first call from the background page is made, and further calls don't do anything (although the background page code keeps running).
Yes, and usually it prompts the user if he/she wants to continue waiting or to kill the page.
Chrome has some limits in place if the JavaScript takes a long time (hence blocks the main thread) it will notify you about taking too much time.
You have two options:
Can you offload some processing to a HTML5 worker and post a message back to the page when processing is complete?
Can you offload some processing to the background page and send a message request back to the content script when processing is complete?
I found out what was the problem. I was using the callback given by the message from the content script to the background html page. This callback can be run only once, because there is only one response allowed for each message send to the background page.
Some sort of bug in chrome causes many responses to work when I added an alert inside the callback function.
The problem was solved by breaking down the content of the message into several messages.

Categories

Resources