4

I have scripts that needs to wait for certain conditions to be met before they run - for example wait for another script to be loaded, or wait for a data object to be created.

How can I manage such dependencies? The only way I can think of is to use setTimeout to loop in short intervals and check the existence of functions or objects. Is there a better way?

And if setTimeout is the only choice, what is a reasonable time interval to poll my page? 50 ms, 100 ms?

[Edit] some of my scripts collect data, either from the page itself or from Web services, sometimes from a combination of multiple sources. The data can be ready anytime, either before or after the page has loaded. Other scripts render the data (for example to build charts).

[update] thanks for the useful answers. I agree that I shouldn't reinvent the wheel, but if I use a library, at least I'd like to understand the logic behind (is it just a fancy timeout?) to try and anticipate the performance impact on my page.

Christophe
  • 27,383
  • 28
  • 97
  • 140
  • Check out [LAB.js](http://labjs.com) or another similar script loader. – Pointy Jan 26 '12 at 15:46
  • setTimeout isn't your best option, can you provide further details? why can't you lunch your script for the script being loaded? – Khodor Jan 26 '12 at 15:46
  • The script needs several conditions to be met: both data to be present and functions to be loaded. It doesn't depend on just another script. – Christophe Jan 26 '12 at 15:56

4 Answers4

2

You could have a function call like loaded(xyz); at the end of the scripts that are being loaded. This function would be defined elsewhere and set up to call registered callbacks based on the value of xyz. xyzcan be anything, a simple string to identify the script, or a complex object or function or whatever.


Or just use jQuery.getScript(url [, success(data, textStatus)] ).

Supr
  • 18,572
  • 3
  • 31
  • 36
1

For scripts that have dependencies on each other, use a module system like RequireJS.

For loading data remotely, use a callback, e.g.

$.get("/some/data", "json").then(function (data) {
    // now i've got my data; no polling needed.
});

Here's an example of these two in combination:

// renderer.js
define(function (require, exports, module) {
    exports.render = function (data, element) {
        // obviously more sophisticated in the real world.
        element.innerText = JSON.stringify(data);
    };
});

// main.js
define(function (require, exports, module) {
    var renderer = require("./renderer");

    $(function () {
        var elToRenderInto = document.getElementById("#render-here");

        $("#fetch-and-render-button").on("click", function () {
            $.get("/some/data", "json").then(function (data) {
                renderer.render(data, elToRenderTo);
            });
        });
    });
});
Domenic
  • 110,262
  • 41
  • 219
  • 271
  • Thanks, this makes sense. The issue in my case is that I have control on the script that consumes the functions and data, not the scripts that load them. That's what I tried to explain in my edit. – Christophe Jan 26 '12 at 20:04
  • Oh, if you don't have control, then you're screwed, and I guess polling is the only option that comes to mind. Maybe those scripts give some kind of hook for you? E.g. firing a custom event you can subscribe to. – Domenic Jan 26 '12 at 20:17
  • I actually posted a question about script onload here http://stackoverflow.com/questions/8956414/cross-browser-onload-event-in-a-static-script-tag . +1 thx for the info about jQuery deferred/then. – Christophe Jan 29 '12 at 23:53
1

There are many frameworks for this kind of thing.

I'm using Backbone at the moment http://documentcloud.github.com/backbone/

Friends have also recommended knockout.js http://knockoutjs.com/

Both of these use an MVC pattern to update views once data has been loaded by a model

[update] I think at their most basic level these libraries are using callback functions and event listeners to update the various parts of the page.

e.g.

model1.loadData = function(){
    $.get('http://example.com/model1', function(response){
        this.save(response);
        this.emit('change');
    });
}

model1.bind('change',view1.update);
model1.bind('change',view2.update);
Qazzian
  • 684
  • 6
  • 9
  • Thanks! This looks like what I'm looking for. Do you think such frameworks could also monitor when scripts are loaded, or do I need to combine them with libraries mentioned in other replies? – Christophe Jan 26 '12 at 20:07
0

I've used pxLoader, a JavaScript Preloader, which works pretty well. It uses 100ms polling by default.

I wouldn't bother reinventing the wheel here unless you need something really custom, so give that (or any JavaScript preloader library really) a look.

Simon Sarris
  • 62,212
  • 13
  • 141
  • 171