Javascript and DOM event interaction and possible race conditions - javascript

Scenario: Preloading images
Perform an ajax query
Show loading screen
Retrieve results from ajax query
Insert images into the dom
Wait for images to finish loading
Hide loading screen
I was thinking of doing the following:
function ajaxCallback(results) {
/* snip insert into dom code */
$(".waitForLoad").each(function() {
imageLoadingCount++;
$(this).load(imageLoaded);
});
}
var imageLoadingCount = 0;
function imageLoaded() {
imageLoadingCount--;
if (imageLoadingCount == 0)
HideLoadingScreen();
}
I'm not quite sure of the interaction between the browser DOM and javascript. Does the DOM wait for the javascript to finish executing before it starts loading the images? I'm worried about possible race conditions.

Javascript should run in parallel with the loading, unless you're using all the connections with AJAX requests. The browser still functions normally while javascript runs, which is the whole point behind it in the first place.

The load event observer is a little scary because it will work only if you set it before the element has completely loaded, if you set it after that nothing will happen. Therefore, it really depends on when you call ajaxCallback(). I would recommend using onSuccess rather than onComplete.
Also, I wonder if it's possible to use the load event observer on $(".waitForLoad") itself?

You can safely execute ajaxCallback within $.ready() and get rid of most problems. And note that DOM is not updated for newly created tags.
Also note that - The HTTP/1.1 specification suggests that browsers download no more than two components in parallel per hostname. If you serve your images from multiple hostnames, you can get more than two downloads to occur in parallel.
In many scenarios, users will get annoyed if you are showing them loading screens for more than a second or two. Waiting for images to get loaded is hardly a good idea.

Related

How to detect DOM update completion after AJAX page load in a Chrome Extension?

I'm trying to identify roughly when the DOM is finished updating after a page is loaded via AJAX on any arbitrary website.
My current method first listens for the chrome.webNavigation.onHistoryStateUpdated event in a background script, then executes a content script in which a MutationObserver detects changes to the website's body. From there, unfortunately, it seems like it's a bit more finicky. If I just wait for the first mutation where nodes are added to the DOM, I wind up in many cases (YouTube, to give one example) where the page is still blank. Other more hacky approaches I've considered include things like just using setTimeout or waiting for the page to reach a certain length, but those seem clearly wide open to exception cases.
Is there a more fool-proof way to detect that the DOM has roughly finished updating? It doesn't necessarily have to be perfectly precise, and erring on the side of triggering late in my use case is better than triggering early. Also it isn't important at all that resources like video and images be fully loaded, just that the text contents of the page are basically in place.
Thanks for your help!

Can I load a javascript file with a partialView in asp.net-mvc?

I have an asp.net-mvc website where there is a top section with a bunch of filter information and the middle section is a reports. I now have a few different report formats and I want to toggle between a few reports. I have it working by making them all partial views and loading them via ajax (to avoid loading the common info over and over again) but one issue i realized is that some of the different reports have different javascript that goes along with them. For now, I am loading up all of the javascript files in the main parent page but I realized that I am wasting a lot of resources by download and wiring up all of the jquery events even if i never actually view a report
Is there anyway I can pass some javascript along with downloading a partial view in asp.net-mvc so I only load this and wire up the events "on demand" as required (instead of always)
Of course you can. Just be aware that the effects of the code will stick around even if you later remove the code itself: any functions you defined will remain defined, any listeners you attached will remain attached (as long as their target elements persist)... so it would be a good idea to make a setup() and teardown() methods for the loading code, that you'd invoke from your controlling code, rather than just drop a bunch of code to execute as it loads.
However, I would say it would need to be a rather unique set of circumstances for me to employ this method; for most part, it would be much easier and efficient to just load all the code you need at once, to benefit from client caching if nothing else. Toggle the behaviour of your code, don't toggle the code.

Backbone.js - CSS change is waiting till javascript is completed - works in Firefox, not in Chrome/Safari

I am having a backbone.js application that I am writing.
When user press a "Search" button, I show a loading.gif image (by making it block), while I let the javascript code to continue. Once the javascript code is complete, I unhide the loading image (changing the display to none).
I am able to see it working in Firefox. In safari/and chrome, the change of CSS don't get applied until the javascript code is completed, and thus user don't see the loading image when the search is being performed.
Any way to fix this?
Thanks
A couple of things strike me as odd.. but to answer your question first:
Most DOM/css changes do not get applied until the executing Javascript returns. To get around this you can make your DOM change and then set a timeout to execute the rest of your Javascript code.
ex:
// make your image visible
function continuation() {
// Put the javascript task that you need to execute here
}
// setTimeout will release execution control back to the browser so your CSS/DOM updates
// can be applied. Once those updates are applied, continuation will be called
// by the browser and your remaining javascript can run.
setTimeout(continuation, 0);
Now it seems odd that you would have any javascript that would take so long to run that you'd have time to even see a loading gif. It would make sense to see a loading image if your are firing an XHR (ajax) request but if you are doing that then you shouldn't be having the issue you are describing. What exactly is this javascript task of yours doing?
I had a similar issue with a loading image which turned out to be because the image hadn't been loaded into the browser and for whatever reason it didn't display until something else completed. I believe in my case an XHR was somehow blocking the loading or display of the image. From memory, this only happened the first time the loading image was displayed, after that it was fine. I ended up adding an element to the page html to load the loading image and then hid it with javascript. This solved the problem..

Ajax: Simultaneous loading of multiple images

I have a grid of pictures (3x3, side by side, laid out in a ). I need to update this grid every so often. Since every picture independent from the rest (they get grabbed from different locations), I elected to load every picture by its own ajax callback, like so:
for (var i=0; i < numPictures; i++) {
Dajaxice.loadPicture(callback_loadPicture, {'picture_id':i})
}
The function callback_loadPicture() puts the picture into its proper place in the .
The problem is: Often, even though some picture will finish loading sooner than others, the browser will not display anything until the last ajax call is finished. Since some calls can time out, this means that I don't see anything until that single picture times out.
This behaves slightly differently in every browser: sometimes the picture will show as the callbacks finish (but usually not), sometimes the browser will show some images, but postpone showing all until the last one is finished loading.
I am using:
django 1.3 (python 2.7)
windows x64 as (test) server
dajaxice for ajax implementation
I am open to changing the structure of my code.
Any comments or suggestions will be appreciated.
Since the ajax calls are blocking as said by chrisdpratt, if you really need to display the images at the same time I would advise some kind of preloading of the 3x3 grid of images and when required by the code you can display them.
With this in mind you can run the code you already have on $(document).ready() but make the images hidden (ie display:none). When later required you would just change the display attribute on the images you need to display.
If the issue you were seeing was indeed caused by the single-threaded implementation of the Django development server, you might try django-devserver (https://github.com/dcramer/django-devserver). Amongst other improvements, it boasts:
"An improved runserver allowing you to process requests simultaneously."
The other improvements make it worth it, too!

JavaScript's get-it-done nature

Is JavaScript intended to be running as little as possible on a website/webapp? By that I mean is the usual intention to run through all your js files as soon as the page loads and put them aside, and then when functions come up to execute them right away and be done with it?
I'm working on a project using google maps and I have a custom marker object scripted out, and a debugger has told me that the browser runs through all my js files before anything even appears on the page.
My problem comes in here: I wanted to animate certain markers to bounce up and down continuously with jQuery (similar to OS X icons in the dock) and my several attempts at infinite loop functions all just crash the browser. So I understand that the browser doesn't like that, but is there a way to have a simple script be repeating itself in the background while the user navigates the page? Or is JavaScript just not supposed to be used that way?
(I worked with Flash for a long time so my mindset is still there.)
Yes, Javascript functions should just do their bit and exit as soon as possible. The GUI and the scripts run on the same single thread, so as long as you are inside a Javascript function, nothing shows up in the browser. If you try to use an infinite loop, the browser will appear to freeze.
You use the window.setInterval and window.setTimeout methods to trigger code that runs at a specific time. By running an interval that updates something several times a second, you can create an animation.
You have to set a timer to execute a script after a defined time.
var timer = setTimeout(code, milliseconds);
will execute code in so-and-so milliseconds. Each execution of the script can set a new timer to execute the script again.
You can cancel a timed event using clearTimeout(timer).
Use setTimeout() or setInterval(). The MDC articles on it are pretty good.
You'll need to update inside of functions that run quickly, but get called many times, instead of updating inside of a loop.
Since you said that you are using jQuery, consider using its effects API (e.g., jQuery.animate()), it will make your life much easier!
Personally, I save as much code as possible for execution after the page has loaded, partly by putting all my <script>s at the bottom of <body>. This means a (perceived) reduction in page load time, whilst having all my JS ready to run when need be.
I wouldn't recommend going through everything you need to do at the beginning of the document. Instead, bind things to events such as clicks of buttons, etc.

Categories

Resources