1

I've got a script inside a body tag. Problem is some code is being loaded before it is finished even though it is in a document ready block. Shouldn't the code in the ready block wait for code in the script tag to finish? Or does it only hold off until the script tag is rendered but not executed?

<html>
<head>
  <script data-main="script.js" src="/assets/js/require.js"></script>
</head>
<body>
  <script type="text/javascript">
    var foo = ${fromServer};

  </script>
</body>
</html>

script.js: And I expect this to wait for until script is complete...

$(function() {
  // access script var from here, not set yet hmmmm
});

I'd love to know what is going on here...

Update:

Okay now, here is the variable from the page

  require.config({
        baseUrl: '/assets/js/app',
        shim: {
            d3: {
                exports: 'd3'
            },
            underscore: {
                exports: '_',
            },
            backbone: {
                deps: ['underscore', 'jquery'],
                exports: 'Backbone'
            },
            uidate: {
                deps: ['jquery']
            }
        },
        paths: {
            d3: '../lib/d3.v3',
            jquery: '../lib/jquery-2.0.3.min',
            underscore: '../lib/underscore',
            backbone: '../lib/backbone'

        }
    });

require([...], function(...) {
  //console.log here and foo is set and good to go
  var myCollection = new MyCollection(foo);

inside MyCollection:

// define(.... {
// var coll = Backbone.Collection.extend({

initialize: function() {
  console.log(this);
}

Looking at the console I see:

 {length: 0, models: Array[0], _byId: Object, constructor: function, model: function…}

When I expand the object in Chrome console there are actually models in there.... strange. If I do a setTimeout inside init and console.log(this) again the models are set. Where is this delay of initialising the models coming from?

I've also tried just loading an array like:

var someColl = new MyCollection([ { ... }, { ... } ]);

Same problem here too.

Update: I've tried to narrow down the scope of the problem, console.log prints an empty array here

var testing = [{x:1,d:2},{x:3,d:8},{x:3,d:98}];
var myCollection = Backbone.Collection.extend({
    initialize: function() {
        console.log(JSON.stringify(this));
    }
});
var x = new myCollection(testing);
el_pup_le
  • 9,721
  • 18
  • 73
  • 126
  • this can help you understand when document.ready is executed http://stackoverflow.com/questions/3698200/window-onload-vs-document-ready – Gyandeep Feb 22 '14 at 04:26
  • What's going on in the creation of the MyCollection object? Is there any asynchronous code in there? Also, `console.log(object)` can lie to you because some browsers like Chrome don't make a copy of the data at the exact instant you do `console.log(obj)` so the actual log may not show the proper data at the instant of the `console.log()` statement. If you `console.log()` an actual value (e.g. a string or number) it will not lie or you can console.log(JSON.stringify(object)) to turn it all into a string and then it won't lie either. – jfriend00 Feb 22 '14 at 06:06
  • Also, what library are you getting `$(function() {})` from? I assumed jQuery, but it looks like maybe you're using something else. – jfriend00 Feb 22 '14 at 06:07
  • Okay it looks like this is related to my problem: http://stackoverflow.com/questions/9354932/why-is-backbone-js-returning-an-empty-array-when-accessing-models – el_pup_le Feb 22 '14 at 06:08
  • There is no asynchronous code in the collection, just initialise and console.log(this) – el_pup_le Feb 22 '14 at 06:09
  • @jfriend00 $(function() {}) is from backbone – el_pup_le Feb 22 '14 at 06:16
  • Yes, it is likely that `console.log()` is lying to you which is confusing your diagnosis. It's suggest you do `console.log(JSON.stringify(this))` instead of `console.log(this)` to see what is actually there and then also change any other `console.log()` statements to only output strings, not objects. – jfriend00 Feb 22 '14 at 06:21
  • hmmm what about using alert? – el_pup_le Feb 22 '14 at 06:21
  • `alert()` is bad because it influences the timing of the code running. `console.log()` with strings only is better. – jfriend00 Feb 22 '14 at 06:22
  • still an empty array if I use stringify, gosh golly – el_pup_le Feb 22 '14 at 06:24
  • Are you 200% sure that the models aren't filled in with an ajax call? – jfriend00 Feb 22 '14 at 06:26
  • yes, there are no ajax calls in the models. – el_pup_le Feb 22 '14 at 06:28
  • Then, what code fills in the models? If they aren't there in the beginning, but are there later, obviously some code somewhere is filling them in. It appears that you need to find out when that code that fills in the models is running. – jfriend00 Feb 22 '14 at 06:52
  • I've defined the model attribute of the collection and the code that fills them in would just be the array I put in the constructor of MyCollection? – el_pup_le Feb 22 '14 at 06:59
  • There is something very wrong with backbone, there is no other explanation – el_pup_le Feb 22 '14 at 07:10
  • @jfriend00 I've updated the question, using a very simple example I get the some empty array in this case. – el_pup_le Feb 22 '14 at 07:28
  • Perhaps it will help you to read [this](https://github.com/jashkenas/backbone/issues/1367), [this](https://github.com/jashkenas/backbone/issues/962) and [this](https://github.com/jashkenas/backbone/issues/814). – jfriend00 Feb 22 '14 at 07:41
  • @jfriend00 perhaps? why yes it does, thank you officer jfriend00 – el_pup_le Feb 22 '14 at 07:50

1 Answers1

2

jQuery ready waits for the DOM to finish loading before calling its callback. This will be roughly equivalent to when the </body> tag is parsed and everything in front of it (including any scripts) has already been parsed. Scripts that are not marked defer or async will have already run.

It isn't entirely clear from your question what exactly your problem is, but code inside a jQuery ready block will be executed after other scripts in the <head> or <body> are executed.

If you are loading scripts asynchronously with the require.js library, then those scripts may load BEFORE or AFTER the document is ready depending upon what else is happening in the document loading. If you need to coordinate timing with when those scripts are loaded asynchronously, then you will have to use the capabilities in the require.js library in order to know when those scripts are loaded or use document.ready in those scripts to make sure they wait for the rest of the document to be parsed.

jfriend00
  • 580,699
  • 78
  • 809
  • 825
  • My problem is that a variable in the script tag (inside body) is empty when accessed from the doc ready callback. I use a setTimeout in the callback and after 1 second the variable is set. So it looks like the doc ready callback doesn't wait for javascript to load in the body. – el_pup_le Feb 22 '14 at 04:38
  • @amiawizard - please show the actual code/structure you're having trouble with. jQuery ready DOES wait for inline ` – jfriend00 Feb 22 '14 at 04:41
  • on your 3rd paragraph, if the code loaded by requirejs is loaded after document is ready then shouldn't the variable from the body script be set by that time? – el_pup_le Feb 22 '14 at 04:41
  • Code loaded by require.js has NO guaranteed load order. It may run before or after jquery ready and, in fact, may vary from time to time. – jfriend00 Feb 22 '14 at 04:43
  • Hmm so is it possible to load a variable from a server side language into a requirejs script? – el_pup_le Feb 22 '14 at 04:47
  • @amiawizard - I have no idea what that last question means? – jfriend00 Feb 22 '14 at 04:49
  • @amiawizard - What does "load a variable from a server side language" mean? – jfriend00 Feb 22 '14 at 04:51
  • I've got data from the server I need loaded into my script – el_pup_le Feb 22 '14 at 04:53
  • @amiawizard - it's generally easier to put data into the HTML page as script variables. It will be available before document.ready if you do it that way. To put data into a script file, you will have to server-side generate the script file. – jfriend00 Feb 22 '14 at 04:54
  • Pardon my ignorance, what do you mean by 'put data into the HTML page as script variables'? – el_pup_le Feb 22 '14 at 05:04
  • @amiawizard - inside an inline ` – jfriend00 Feb 22 '14 at 05:07
  • That's what I'm doing but requirejs loads before the script hence my problem :( I need to access server data with a requirejs script – el_pup_le Feb 22 '14 at 05:08
  • @amiawizard - if you place the inline script with your variables before the require.js call to load your other script, then the variable HAS to be available first. – jfriend00 Feb 22 '14 at 05:11
  • @amiawizard - you could also use `jquery.ready` in your require.js script and all variables defined within your HTML page will be ready before the jquery.ready callback runs. – jfriend00 Feb 22 '14 at 05:14
  • I am using: $(function() { ... }); – el_pup_le Feb 22 '14 at 05:15
  • This is strange, I've got a loop after the variable to do some parsing, a simple loop that probably take < 0.01ms yet it's not finished parsing by the time the requirejs script tries to access the variable. strange. – el_pup_le Feb 22 '14 at 05:16
  • @amiawizard - look this is kind of pointless for me to keep trying to guess what you're real code is. Why don't you just put your real code into your question so we can see what's really going on? – jfriend00 Feb 22 '14 at 05:16
  • Please don't raise your voice in my presence. – el_pup_le Feb 22 '14 at 05:18
  • @amiawizard - no voice raising here - just frustration that you won't show the actual problem. And, frankly I'm tired of guessing. – jfriend00 Feb 22 '14 at 05:19
  • Okay then it's your attitude, anyway I've deduced that it has nothing to do with page load ordering, the variable is set in the requirejs script BUT once I create a new backbone collection with the models, this.models is empty, 1 second later after a setTimeout, this.models has it's models. Strange indeed. – el_pup_le Feb 22 '14 at 05:33
  • @amiawizard - where is the variable you want to use actually defined and given its value? In an inline ` – jfriend00 Feb 22 '14 at 05:38
  • I think it's best I post the code, one second please. – el_pup_le Feb 22 '14 at 05:40