views:

553

answers:

5

Hi, 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?

+1  A: 

If you don't mind having a preprocessing step, try Narrative Javascript, which you can

image.onload = new EventNotifier();
image.onload.wait->();
KennyTM
That is a great project but i'm trying to build a simple application in pure javascript...and i don't know anything about Java:)
mck89
@mck89: After the preprocessing you get pure Javascript.
KennyTM
Yeah i know but i prefer to use only javascript
mck89
From what I can tell, all Narrative JavaScript does is creates the necessary callbacks for you. It doesn't stop script execution (because other parts of the script can still be run).
Andy E
@Andy: So you think the OP wants a checking loop (`while(!image.loaded){}`)?
KennyTM
@KennyTM: That's not what I said (and my answer said that is the **only** way to block script execution). I think the OP should change his code to work using callbacks/event handlers.
Andy E
+1  A: 

The only way to block script execution is to use a loop, which will also lock up the browser and prevent any interaction with your web page. Even if you would be happy doing this (and it's a horrible way to go about things if you ask me), I can't think of a way you could check to see if the image is actually loaded from inside the loop.

EDIT
Firefox and IE (at least) support the complete property, although I can't see it in the DOM specification. Other browsers may support it too.

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.

Andy E
I agree that this is a bad way but i think also that it's the only way. Maybe i can give the user the possibility to choose between blocking script execution and call the loading function when the image is loaded.
mck89
@mck89: I find it hard to believe it's the only way. I can honestly say I've never come across a situation in JavaScript that requires locking up the script; there's always a way (such as temporarily overriding functions) to do things asynchronously. You're in control of the script on your page, after all. Maybe you could post another question going into more detail about your problem?
Andy E
@mck89: The `complete` property exists for Gecko and IE and might work in other browsers too. If you're insistent on blocking script execution, see my update.
Andy E
Yeah i think that i will use something like this thanks for your help.
mck89
+1  A: 

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?

Upper Stage
Yes this could be a good preloading method for images but i'm not loading the image at the beginning of the application.
mck89
I understand, but if you created a CSS class with a background-image attribute, assigned that class to a dummy DIV, you WOULD BE loading the image at the beginning of the application.
Upper Stage
A: 

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;
   }
}
FlashXSFX
Are you sure that you can stop the execution with setTimeout?
mck89
This doesn't stop code execution, it allows you to wait until the image is done loading before you do any more work. You 'stop' doing your own code execution by moving your remaining code into the finishWork function.
FlashXSFX
A: 

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);

This does assume that the image is served with cache friendly http headers. Otherwise, it's behavior might vary in different browsers.

chris