I would like to know why in Chrome, this line:
var quer = confirm("Deseja esta poltrona?");
loads before the previous line:
imagens[i].src = "img/poltrona_selecionada.jpg";
On Firefox, te function works perfectly in the sequence.
This is my function:
function selecionarPoltrona() {
var imagens = document.getElementsByTagName("img");
for (var i=0; i<poltronas.length; i++) {
if (poltronas[i]) {
imagens[i].src = "img/poltrona_selecionada.jpg";
var quer = confirm("Deseja esta poltrona?");
if (quer) {
break;
} else {
imagens[i].src = "img/poltrona_disponivel.jpg";
}
}
}
}
Thank You
Welcome to the Image object, and <img> element: it is not synchronous. When you tell an image what its source is, the rest of your code gets to keep running. It does not wait for the image binding to succeed, the image URL to be looked up, the data the be transfered, the bytes to be decoded, all before you see the image. This all happens while the rest of your code runs. However, confirm (and alert, and prompt, and all those terrible functions) don't: they block the thread. So this happens:
You set the image .src attribute, and the browser schedules this for off-thread handling. Your code continues
confirm gets triggered, and everything stops. Nothing will happen in your tab until the confirm is deal with.
you click through the confirm. Javascript runs again, and the browser's image source binding runs again.
after X amount of time, your image is done downloading, parsing, and finally renders.
If you want some code to run after the image finishes all its work, you do this:
...
img.onload = function() {
// the code you need to have run after the image finishes loading.
}
img.onerror = function() {
// whatever we need to do if the image cannot load.
}
img.src = "..." // trigger the image loading attempt
Or, using modern rather than 1998 JS:
...
img.addEventListener("load", function(evt) {
// the code you need to have run after the image finishes loading.
});
img.addEventListeners("error", function(evt) {
// whatever we need to do if the image cannot load.
});
img.src = "..." // trigger the image loading attempt
Related
I am playing with image loading and stuck on sequentially executing the code
function processImage(callback) {
console.log("Start");
callback('http://lorempixel.com/400/200/');
console.log("Finish");
}
function loadImage(url) {
console.log('Load Method')
var img = new Image();
img.src = url;
img.onload = function (event) {
console.log('Image Loaded')
}
}
processImage(loadImage);
For the above code, I want the output as Start -> Load Method -> Image Loaded -> Finish
Instead, I am getting Start -> Load Method -> Finish -> Image Loaded
I am having trouble using callback method I guess.
Any help appreciated.
img.onload is setting an event listener - so when the event occurs, it'll call the function. So, unless your image loads in about a millionth of second (the amount of time I guess it takes JS to go to the next line), the console.log("Finish") will happen first.
When the image is fully loaded, the function which is set to .onload is called. As the image loads after JavaScript has processed the next line, this one will happen first. If you really want to indicate the start and finish, put your finish console.log after the image loaded console.log.
img.onload = function (event) {
console.log('Image Loaded')
console.log('Finish)
}
What is the best way to use the jQuery load function synchronously.
I need to load an image but can't execute the next line of code until that image has loaded.
I could loop a variable until the load has completed but was wondering if there was a better way of doing that.
var img = jQuery('<img src="' + url + '"/>').load(function () {
});
//Run code here once img load has comlpeted.
You can also use CallBack function to get Synchronous Behaviour -
var result = $('#main-container').load( 'html/Welcomeform.html',
function () {
if($("textarea").find("#mail-id")){
$("textarea#mail-id").val(email_id);
}
} );
From what I know, the load event will always fire asynchronously, except if the image is already cached (in some browsers). The only reliable solution is to put the code in a callback like you did. However, to make sure the load handler will always be fired in all browsers, even if the image is cached, make sure to add the handler before setting the src property of the image.
var img = jQuery('<img src="' + url + '"/>').load(runner);
function runner() {
//run code here once image is loaded
}
I arrived here looking for a similar solution. From the reads, it is not possible with .load, you need to use an AJAX request, as the question comment points out.
In my case I need to load a html file and I have added a transition to change the content. The old content were showed before the new one after the transition even if I was showing the content inside the load callback.
var main = $("#main");
main.load("about.html", displaySection);
function displaySection () {
main.show('blind');
}
My workaround has been to run the transition that shows the loaded content inside a timeout function with a of 200 for the delay parameter.
var main = $("#main");
main.load("about.html", displaySection);
function displaySection () {
setTimeout(function() {
main.show('blind');
}, 200);
}
The problem could be if the connection is so slow that the new page takes more than 200 ms to load, but in this case I wonder the callback will be launched later on. I don't understand why is not working without the timeout that I feel quite ugly, but it solved my problem ... just in case any other has not given a thought on this possibility.
The callback function in load() will fire once the basic elements of the screen have been retrieved, (the actual html) but doesn't wait for images to finish, you can use this to make it wait.
$('#holder').load(function() {
var imgcount = $('#holder img').length;
$('#holder img').load(function(){
imgcount--;
if (imgcount == 0) {
/* now they're all loaded, let's display them! */
}
});
});
What console log can be after this code will be executed?
var img = new Image;
img.onload = function() { console.log('B'); };
img.src = 'image.jpg';
for (var i=0;i<100000;i++) {
console.log('A');
}
I know, that most likely it will be A...AB.
But can it be A...B...A or BA...A? For example, if image.jpg is very small file and connection is very fast.
It can be any of them. You don't know how long it takes to load the image. The image could even be cached, minimizing the loading time.
I need to load an array of images in Javascript, but I want to make sure that all the images are loaded before starting drawing them. So, I busy-wait for every image onLoad event to be called. First I create images and set their source and onload function:
// Load images from names
for (i = 0; i < this.nImages; i++) {
this.imagesArray[i] = new Image();
this.imagesArray[i].onload = this.onLoad(i);
this.imagesArray[i].src = images[i];
}
This is the onLoad function, member of the class I'm developing (the first two steps were in the constructor):
MyClass.prototype.onLoad = function (nimage) {
console.log ("Image completed? ", nimage, " ", this.imagesArray[nimage].complete);
this.imagesLoaded++;
}
Then I busy wait for all the onLoad functions to increment the counter (again, in the constructor):
while (this.imagesLoaded < this.nImages) {
// This is busy wait, and I don't like it.
continue;
}
So far, so good. But when I try to draw it on an HTMl5 canvas with my drawClass:
MyClass.prototype.refresh = function () {
// Gets one of the images in the range
var imageNum = this.GetImageNum();
// Test for completeness. This gives FALSE :(
console.log ("completeness for image number ", imageNum, " is: ", this.imagesArray[imageNum].complete);
this.drawClass.draw(this.imagesArray[imageNum], this.xOrigin, this.yOrigin);
}
The console.log line gives false and I get the infamous NS_ERROR_NOT_AVAILABLE exception.
Please not that the refresh() function is called after the onLoad() function, according to Firebug.
What am I missing here?
You need to assign onload before setting the source, otherwise the loading may be completed before the script gets to set the handler. Maybe that already fixes it.
Re the busy waiting, that is indeed never a good thing. It's hard to suggest alternatives, as you are not showing why you need to wait in the first place. But what might be a good idea is extending the onload handler to detect whether the image array is complete, and if it is, to start the following action - that would make the busy waiting unnecessary.
I need to do something like this:
Execute a piece of code
Start to load an image and block the script execution
When the image is loaded resume the execution
Execute the rest of the code
I know that the simplest way is to assign a function on the onload event of the image and then execute the rest of the code in the function, but if it's possible i want to have a "linear" behaviour blocking the script execution and then resume it.
So, is there a cross-browser way to do this?
The only way to block script execution is to use a loop, which will also lock up most browsers and prevent any interaction with your web page.
Firefox, Chrome, Safari, Opera and IE all support the complete property, which was finally standardised in HTML5. This means you can use a while loop to halt script execution until the image has finished downloading.
var img = new Image();
img.src = "/myImage.jpg";
document.body.appendChild(img);
while (!img.complete)
{
// do nothing...
}
// script continues after image load
That being said, I think you should look at ways of achieving your goal without locking up the browser.
If you don't mind having a preprocessing step, try Narrative Javascript, which you can
image.onload = new EventNotifier();
image.onload.wait->();
This suggestion is not exactly what you asked for, but I offer it as a possible alternative.
Create a CSS class with the background-image you want to use. When your app starts, assign this CSS class to a DIV that is either hidden out of site or sized to zero by zero pixels. This will ensure the image is loaded from the server. When you want to load the image (step two above), use the CSS class you create; this will happen quickly. Maybe quickly enough that you need not block the subsequent code execution?
I wouldn't try to block script execution completely, as that could make the browser slow down, or even alert the user that a script is taking too long to execute.
What you can do is 'linearize' your code by using events to finish work. You will need to add a time out to the function, as the image may never load.
Example:
var _img = null;
var _imgDelay = 0;
var _finished = false;
function startWork(){
_img = document.createElement('img');
_img.onload = onImgLoaded;
_img.src = 'yourimg.png';
// append img tag to parent element here
// this is a time out function in case the img never loads,
// or the onload event never fires (which can happen in some browsers)
imgTimeout();
}
function imgTimeout(){
if (_img.complete){
// img is really done loading
finishWork();
}
else{
// calls recursively waiting for the img to load
// increasing the wait time with each call, up to 12s
_imgDelay += 3000;
if (_imgDelay <= 12000){ // waits up to 30 seconds
setTimeout(imgTimeout, _imgDelay);
}
else{
// img never loaded, recover here.
}
}
}
function onImgLoaded(){
finishWork();
}
function finishWork(){
if (!_finished){
// continue here
_finished = true;
}
}
You can use xmlhttprequest and use synchronous mode.
var url = "image.php?sleep=3";
var img = new Image;
var sjax = new XMLHttpRequest();
img.src = url;
sjax.open("GET", url, false);
sjax.send(null);
alert(img.complete);
The trick here is we load the same image twice, first by using the Image object, and also by using ajax in synchronous mode. The Image object isn't needed, I just assumed that's how you want to load it. The key though is that if ajax completes, then the image will be fully downloaded an in the browser's cache. As such, the image will also be available for use by the Image object.
This does assume that the image is served with cache friendly http headers. Otherwise, it's behavior might vary in different browsers.