Is there any way to know how far browser loaded the page?
Either by using JavaScript or browser native functions.
Based on the page status i want to build progress bar.
I'm not 100% sure this will work, but.. here is the theory:
First of all, don't stop JavaScript running until the page has loaded. Meaning, don't use window.ready document.ready etc..
At the top of the page initialise a JavaScript variable called loaded or something and set it to 0.
var loaded = 0;
Throughout the page increment loaded at different points that you consider to be at the correct percentages.
For example, after you think half the page would have been loaded in the code set loaded = 50;.
Etc..
As I say, this is just a concept.
Code:
function request() {
showLoading(); //calls a function which displays the loading message
myRequest = GetXmlHttpObject();
url = 'path/to/script.php';
myRequest.open('GET',url,true);
myRequest.onreadystatechange = function() {
if(myRequest.readyState == 4 && myRequest.status == 200) {
clearLoading(); //calls a function which removes the loading message
//show the response by, e.g. populating a div
//with the response received from the server
}
}
myRequest.send(null);
}
At the beginning of the request I call showLoading() which uses Javascript to dynamically add the equivalent of your preLoaderDiv. Then, when the response is received, I call clearLoading() which dynamically removes the equivalent of your preLoaderDiv.
You'll have to determine it yourself, and to do that you'll have to have a way to determine it. One possibility is to have dummy elements along the page, know their total, and at each point count how many are already present. But that will only give you the amount of DOM obtained, and that can be a very small part of the load time - most often than not, the browser is idle waiting for scripts and images.
Related
Premise: I need to apply changes trough JavaScript because the free platform on which my site is based does not allow changes to some parts of the template, so I can't insert the scripts in the source through the tag, but I can insert them in the script administration panel provided by the platform.
The script put in the panel are normally called up before the building of the DOM tree, so I have to insert the scripts in the $(function) to force the call at the end of the dom tree building, but in this way the function is called after the page has been drawn and the user first sees the old page and then the new page generating a "single buffering" effect.
Summarize:
1 - browser loading page and display it
2 - browser loading image and display it
3 - browser execute script and display changes
Quite often the point two take about 1 seconds or more so the old page is displayed for that time.
Can I force javascript to run code between point one and point two, so that point three become point two, and point two become point three?
I try:
$(function) {}
$(window).onload() {}
$(document).ready() {}
document.addEventListener('DOMContentLoaded', function() {});
Nothing of these works as I want.
Thank you in advance for help.
Solution found:
// add 'timer' function which will be called once every millisecond
var step = setInterval(step, 1);
function step() {
// verify if element is loaded
if (document.getElementById('*element-id*')) {
// add code here
// stop function call
window.clearInterval(step);
}
}
This work very well for me.
I'm learning javascript by creating a program which requests an API and dispays various properties (price in this example) to html. I have a few questions about my code and some problems I've been facing.
1). I have a bunch of $.getJSON functions corresponding to each value that I want to retrieve. I put them all in a a single 2 min. timer. When the page FIRST loads, however, some of the html elements fail to load at all. But if I refresh the page, they sometimes do load. If I refresh again, they might not load at all again. Every time I refresh, there's like a 10% chance of that particular function not inserting the content in the element. If it does load and I leave the page open, it will correctly function (update its value and html element every 2 mins and add/remove the green and red classes). If it doesn't load and I leave the page open, it will correctly function in 2 mins when the 2nd api request is made. I have already tested that the variables have some value (are not null) before and after each $('#price').text('$' + price);.
Here's an example of a function that does that:
var tempPrice;
var myVar = setInterval(myTimer, 1200000);
myTimer();
function myTimer() {
$.getJSON(link, function (json) {
$.each(json, function (index, value) {
if (value.id == "price") {
var price = value.price_eur;
if (!tempPrice) {
$('#price').text('$' + price);
tempPrice = parseFloat(price);
}
if (parseFloat(price) !== tempPrice) {
$('#price').text('$' + price).removeClass();
if (parseFloat(price) > tempPrice) {
setTimeout(function () {
$('#price').addClass("green");
}, 1);
} else {
setTimeout(function () {
$('#price').addClass("red");
}, 1);
}
tempPrice = parseFloat(price);
}
}
});
});
// Many more $.getJSON functions below...
}
If I run this function alone on either jsfiddle or my dev server (flask), it works fine. It only breaks down when I use it in conjunction with more api requests. If I remember correctly, I didn't have this problem before when I used to have a separate timer for each $.getJSON function and put each in its own <script> tag directly in html.
2) I know I can loop through the json instead of using $.each. How else can I improve the code?
1
As for the problem you're having with the inconsistent behavior of the initial page loading, it's because you are executing JavaScript before giving the browser the time to load the page fully first. You can solve this simply by waiting for the page the load, and then executing your code.
Example in jQuery:
$(document).ready(function() {
// Page is loaded, execute code...
});
2
To help you improve the way you're handling the supplied JSON data, a sample of the data would be useful.
sorry if this thread is repited but i didn't find it in browser.
I want to create/handle an event that let me know when a specific resource load into the web page. (similar to onload or DOMContentLoaded, BUT i need to know when each resource finish, not the whole page)
Example--> Assets = image1,image2,image3,...
when finish loading image1 trigger a ready event,
After ready event triggered start loading image2
keep going...keep going....
After last image, trigger again ready event.
The final result is the same as DOMContentLoaded or "windows.onload", but as i said im not abble to put some logic in the middle of assets load.
Someone know how to handle that kind of thing?
I am not sure, why (or if) you want to 'load' the images in a specific order. Be aware that browsers rarely open a single connection. Normally all resources will be collected (after downloading the html itself) and the browser will load many of them in parallel. In short - in case you do this for performance or speed, you would slow down the process!
A more common approach to lazy load images is using the viewport / scroll position to decide which images should be loaded "next", there are a few jquery plugins, e.g. lazyload.
Anyway - in case you do not care about the order and you just want to a element specific callback when ready you could do something like this:
$("img").one("load", function() {
var $this = this;
// 'this' is your specific element
// do whatever you like to do onready
}).each(function() {
// handle cached elements
if(this.complete) $(this).load();
});
In case you do care about the order and you really want to load the next image after the first one is ready you need a different approach.
First: Your HTML does not contain image sources, but images with a data-attribute(s):
<img data-src="the/path/to/your/image" data-assets-order="1" />
Second: In JS you collect all these images without a real source, you order the collection and finally trigger the loading one after each other.
var toLoad = [];
// scanning for all images with a data-src attribute
// and collect them in a specified order.
$('img[data-src]').each(function() {
// either you define a custom order by a data-attribute (data-assets-order)
// or you use the DOM position as the index. Mixing both might be risky.
var index = $(this).attr('data-assets-order') ?
$(this).attr('data-assets-order') : toLoad.length;
// already existing? put the element to the end
if (toLoad[index]) { index = toLoad.length; }
toLoad[index] = this;
});
// this method handles the loading itself and triggers
// the next element of the collection to be loaded.
function loadAsset(index) {
if (toLoad[index]) {
var asset = $(toLoad[index]);
// bind onload to the element
asset.on("load", function() {
// in case it is ready, call the next asset
if (index < toLoad.length) {
loadAsset(index + 1);
}
});
// set the source attribut to trigger the load event
asset.attr('src', asset.attr('data-src'));
}
}
// we have assets? start loading process
if (toLoad.length) { loadAsset(index); }
I'm not sure if this will work for you, but did you tried the setTimeOut function?
You can set a specific time for your image to load (through ajax, you can make the call to the resource and wait until request.done), and after that, call to the next one.
I also found something 'similar' to your request here:
How to wait for another JS to load to proceed operation?
Sorry if this doesn't help you.
I have a small chat implementation, which uses a Message model underneath. In the index action, I am showing all the messages in a "chat-area" form. The thing is, I would like to start a background task which will poll the server for new messages every X seconds.
How can I do that and have my JS unobtrusive? I wouldn't like to have inline JS in my index.html.erb, and I wouldn't like to have the polling code getting evaluated on every page I am on.
This would be easiest using a library like mootools or jquery. On domready/document.ready, you should check for a given class, like "chat-area-container". If it is found, you can build a new <script> tag and inject it into DOM in order to include the javascript specific for the chat area. That way, it isn't loaded on every page. The "chat-area-container" can be structured so that it is hidden or shows a loading message, which the script can remove once it is initialized.
On the dynamically created <script> tag, you add an onLoad event. When the script is finished loading, you can call any initialization functions from within the onLoad event.
Using this method, you can progressively enhance your page - users without javascript will either see a non-functioning chat area with a loading message (since it won't work without js anyway), or if you hide it initially, they'll be none-the-wiser that there is a chat area at all. Also, by using a dynamic script tag, the onLoad event "pseudo-threads" the initialization off the main javascript procedural stack.
To set up a poll on a fixed interval use setInterval or setTimeout. Here is an example, using jQuery and making some guesses about what your server's ajax interface might look like:
$(function() {
// Look for the chat area by its element id.
var chat = $('#chat-area');
var lastPoll = 0;
function poll() {
$.getJSON('/messages', { since: lastPoll }, function(data) {
// Imagining that data is a list of message objects...
$.each(data, function(i, message) {
// Create a paragraph element to display each message.
var m = $('<p/>', {
'class': 'chat-message',
text: message.author +': '+ message.text;
});
chat.append(m);
});
});
// Schedules the function to run again in 1000 milliseconds.
setTimeout(poll, 1000);
lastPoll = (new Date()).getTime();
}
// Starts the polling process if the chat area exists.
if (chat.length > 0) {
poll();
}
});
I don't want to know a way to preload images, I found much on the net, but I want to know how it works.
How is javascript able to preload images?
I mean, I tried a snippet from here, and even if it works, it doesn't seem to preload images.
When I check firebug, I can see that the image is loaded twice, once while the preloading, another time when displaying it!
To improve this code I'd like to know how it works.
Here is what i do:
function preload(arrayOfImages) {
$(arrayOfImages).each(function(){
$('<img/>')[0].src = this;
//(new Image()).src = this;
alert(this +' && ' + i++);
});
}
then i do something like that:
preloader = function() {
preload(myImages);
}
$(document).ready(preloader);
Here is how i display/add the image :
$("li.works").click(function() {
$("#viewer").children().empty();
$('#viewer').children().append('<img src=\'images/ref/'+this.firstChild.id+'.jpg\' alt="'+this.firstChild.id+'" \/>')
$("#viewer").children().fadeIn();
Your basic Javascript preloader does this:
var image = new Image();
image.src = '/path/to/the/image.jpg';
The way it works is simply by creating a new Image object and setting the src of it, the browser is going to go grab the image. We're not adding this particular image to the browser, but when the time comes to show the image in the page via whatever method we have setup, the browser will already have it in its cache and will not go fetch it again. I can't really tell you why whatever you have isn't working this way without looking at the code, though.
One interesting gotcha that is discussed in this question is what happens when you have an array of images and try preloading them all by using the same Image object:
var images = ['image1.jpg','image2.jpg'];
var image = new Image();
for(var x = 0; x < images.length; x++) {
image.src = images[x];
}
This will only preload the last image as the rest will not have time to preload before the loop comes around again to change the source of the object. View an example of this. You should be able to instantly see the second image once you click on the button, but the first one will have to load as it didn't get a chance to preload when you try to view it.
As such, the proper way to do many at once would be:
var images = ['image1.jpg','image2.jpg'];
for(var x = 0; x < images.length; x++) {
var image = new Image();
image.src = images[x];
}
Javascript preloading works by taking advantage of the caching mechanism used by browsers.
The basic idea is that once a resource is downloaded, it is stored for a period of time locally on the client machine so that the browser doesn't have to retrieve the resource again from across the net, the next time it is required for display/use by the browser.
Your code is probably working just fine and you're just misinterpeting what Fire Bug is displaying.
To test this theory just hit www.google.com with a clean cache. I.e. clear your download history first.
The first time through everything will likely have a status of 200 OK. Meaning your browser requested the resource and the server sent it. If you look at the bottom on the Fire Bug window it will says how big the page was say 195Kb and how much of that was pulled from cache. In this case 0Kb.
Then reload the same page without clearing your cache, and you will still see the same number of requests in FireBug.
The reason for this is simple enough. The page hasn't changed and still needs all the same resources it needed before.
What is different is that for the majority of these requests the server returned a 304 Not Modified Status, so the browser checked it's cache to see if it already had the resource stored locally, which in this case it did from the previous page load. So the browser just pulled the resource from the local cache.
If you look at the bottom of the Fire Bug window you will see that page size is still the same (195Kb) but that the majority of it, in my case 188Kb, was pulled locally from cache.
So the cache did work and the second time i hit Google I saved 188Kb of download.
I'm sure you will find the same thing with preloading your images. The request is still made but if the server returns a status of 304 then you will see that the image is in fact just pulled from local cache and not the net.
So with caching, the advantage is NOT that you kill off all future resource requests, i.e. a Uri lookup is still made to the net but rather that if possible the browser will pull from the local cache to satisify the need for the content, rather than run around the net looking for it.
You may be confused by the concept of "preloading". If you have a bunch of images in your HTML with <img src="...">, they cannot be preloaded with Javascript, they just load with the page.
Preloading images with Javascript is about loading images not already in the document source, then displaying them later. They are loaded after the page has rendered for the first time. They are preloaded in order to eliminate/minimize loading time when it comes to making them appear, for example when changing an image on mouse rollover.
For most applications, it is usually better practice to use "CSS sprites" as a form of preloading, in lieu of Javascript. SO should have a ton of questions on this.
It just involves making a new DOM image object and setting the src attribute. Nothing clever and AFAIK, it has always worked for me.
Is it possible the second "load" firebug is showing you is it loading it from cache?
The index on the loop is only looking
at the first image. Change it to use
the index:
function preload(arrayOfImages) {
$(arrayOfImages).each(function(i){ // Note the argument
$('<img/>')[i].src = this; // Note the i
//(new Image()).src = this;
alert(this +' && ' + i++);
});
}
Edit: In retrospect, this was wrong and I can see you're trying to create image elements. I don't understand why the index is there at all, there need not be an index. I think the function should look like this:
function preload(arrayOfImages) {
$(arrayOfImages).each(function () {
$('<img/>').attr('src', this);
});
}
And to instantiate it, why not just do this:
$(function () { // Equivalent to $(document).ready()
preload(myImages);
});
JavaScript image preloading works because when a DOM element that contains an image is created, the image is downloaded and cached. Even if another request is made when the image is actually rendered from the HTML, the server will send back a 304 (not changed), and the browser will simply load the image from its cache.
Paolo suggests using the following notation to create an image object:
var image = new Image();
While this will work, the DOM-compliant way of doing this is:
var image = document.createElement('img');
image.setAttribute('src', 'path/to/image.jpg');
Which is the way it is being done in the script, except it's using jQuery's HTML string literal syntax to do it. Additionally, most modern browsers offer compatibility with the Image() constructor by simply calling DOM-standard methods. For example, if you open up the Google Chrome JavaScript console and type Image, this is what you'll get:
function Image() {
return document.createElementNS('http://www.w3.org/1999/xhtml', 'img');
}
Chrome merely uses the native DOM methods to create an image element.