SitePoint Sponsor

User Tag List

Results 1 to 14 of 14
  1. #1
    SitePoint Enthusiast
    Join Date
    Feb 2012
    Posts
    55
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    What does this idiom mean?

    I'm trying to understand an application I use, and I've encountered a JavaScript idiom that I don't recognize.

    The HTML page contains an inline script which contains the following code (the names are changed to protect the innocent):

    Code:
    $(function() {
      window.foo = new foo({...});
      window.foo.load();
    });
    ("{. . .}" represents a definition of a large object which I understand, and which isn't relevant.)

    I see that the inner code creates an anonymous function which, when run, will create a new object of class foo, assign it to a property named foo on the window object, and execute the load method of the object.

    But what does $( . . . ) mean? I'm familiar with the JavaScript idiom of creating a function named $ which returns a page element when given the element's name, but I don't think that's what is happening here. If it were, the code would be returning a page element whose name is an anonymous function -- and then doing nothing with it. Neither half of that makes sense!

  2. #2
    It's all Geek to me silver trophybronze trophy
    ralph.m's Avatar
    Join Date
    Mar 2009
    Location
    Melbourne, AU
    Posts
    24,112
    Mentioned
    448 Post(s)
    Tagged
    8 Thread(s)
    Quote Originally Posted by Orthoducks View Post
    what does $( . . . ) mean?
    That's common syntax for a library like jQuery. It's a function that calls on the library to do its thing, so there would need to be a link to the library above this code.
    Facebook | Google+ | Twitter | Web Design Tips | Free Contact Form

    Forum Usage: Tips on posting code samples, images and more

    Forrest Gump: "IE is like a box of chocolates: you never know what you're gonna get."

  3. #3
    Community Advisor bronze trophy
    fretburner's Avatar
    Join Date
    Apr 2013
    Location
    Brazil
    Posts
    1,388
    Mentioned
    45 Post(s)
    Tagged
    12 Thread(s)
    When you call jQuery, passing in an anonymous function in this way:

    Code JavaScript:
    $(function() { .. });

    it's a basically a shortcut for doing this:

    Code JavaScript:
    $(document).ready(function(){ .. });

    which means that you're asking jQuery to execute the enclosed code as soon as the DOM is ready.

    It's actually almost never necessary to use though, as if you include your JS files immediately before the document's closing </body> tag they wont actually be loaded and executed by the browser before the all the page markup has been loaded anyway.

  4. #4
    Programming Since 1978 silver trophybronze trophy felgall's Avatar
    Join Date
    Sep 2005
    Location
    Sydney, NSW, Australia
    Posts
    16,786
    Mentioned
    25 Post(s)
    Tagged
    1 Thread(s)
    Quote Originally Posted by fretburner View Post
    It's actually almost never necessary to use though,
    Why did you say "almost"? It is never necessary to test if the DOM has loaded if the script is correctly positioned before the </body> tag.

    The only exceptions to scripts being able to run straight away at that point are the couple of types that must go in the head (because they need to run before the DOM starts to load) and theose that will only run of other files in the page fail to load (where the script needs to wait for the load event).
    Stephen J Chapman

    javascriptexample.net, Book Reviews, follow me on Twitter
    HTML Help, CSS Help, JavaScript Help, PHP/mySQL Help, blog
    <input name="html5" type="text" required pattern="^$">

  5. #5
    SitePoint Enthusiast
    Join Date
    Feb 2012
    Posts
    55
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thank you. When I first read the explanation I wondered what the difference was between

    Code:
    $(function() {
      window.foo = new foo({...});
      window.foo.load();
    });
    and

    Code:
      window.foo = new foo({...});
      window.foo.load();
    I gather that if the script is in the head, the first is executed when the DOM is fully loaded, and the second is executed immediately. If the script is in the body, there's no difference. Is that correct?

    Can you explain why the function definition works that way? It will be easier to remember if there's a rationale for it, something more than "remember that this does that"!

  6. #6
    Community Advisor bronze trophy
    fretburner's Avatar
    Join Date
    Apr 2013
    Location
    Brazil
    Posts
    1,388
    Mentioned
    45 Post(s)
    Tagged
    12 Thread(s)
    Quote Originally Posted by Orthoducks View Post
    I gather that if the script is in the head, the first is executed when the DOM is fully loaded, and the second is executed immediately. If the script is in the body, there's no difference. Is that correct?
    Yes, although just to clarify, the script needs to be the last tag within the body. If you put it halfway through, the script would be executed before the second half was ready.

    Quote Originally Posted by Orthoducks View Post
    Can you explain why the function definition works that way? It will be easier to remember if there's a rationale for it, something more than "remember that this does that"!
    That's just the way jQuery does things. If you pass in a string of selectors, you'll get back any matching elements from the DOM. If you pass in a callback, it'll be executed on DOM ready. See here for details on the arguments you can pass to the jQuery function, and there's some more info on the DOM ready stuff here.

  7. #7
    Community Advisor bronze trophy
    fretburner's Avatar
    Join Date
    Apr 2013
    Location
    Brazil
    Posts
    1,388
    Mentioned
    45 Post(s)
    Tagged
    12 Thread(s)
    Quote Originally Posted by felgall View Post
    Why did you say "almost"? It is never necessary to test if the DOM has loaded if the script is correctly positioned before the </body> tag.
    Because there is at least one legitimate use for DOM ready function that I already mentioned in a previous thread - when using asynchronous script loaders.

  8. #8
    Gre aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    5,889
    Mentioned
    208 Post(s)
    Tagged
    12 Thread(s)
    Quote Originally Posted by felgall View Post
    It is never necessary to test if the DOM has loaded if the script is correctly positioned before the </body> tag.
    I ran into a case last week, where using $(document).ready(function(){ ... }), would have saved me a good half an hour.
    I was working on a Rails 3 app to which I wanted to add some JavaScript functionality.
    By convention, if this JavaScript should be available on every page, you add your code to a file called "application.js"
    So, I wrote what I thought would work, stuck it in "application.js", but no dice.
    I then spent quite a while debugging why what I thought would work, wasn't working, only to realize that in (at least) development mode, Rails 3 includes "application.js" in the <head> of the document. All I had to do after that was wrap everything in $(function(){ ... })

    You could argue that the Rails guys did something wrong by including the file there, or perhaps they have a use case that I didn't think about, or then again maybe I am meant to configure something somewhere, so that the file is positioned before the </body> tag.

    Whatever the case, I just wanted to share that.

  9. #9
    Programming Since 1978 silver trophybronze trophy felgall's Avatar
    Join Date
    Sep 2005
    Location
    Sydney, NSW, Australia
    Posts
    16,786
    Mentioned
    25 Post(s)
    Tagged
    1 Thread(s)
    Quote Originally Posted by fretburner View Post
    Because there is at least one legitimate use for DOM ready function that I already mentioned in a previous thread - when using asynchronous script loaders.
    What difference does loading JavaScript asynchronously make? Since the DOM is already loaded by the time the script to start the asynchronous load is called just before the </body> tag there should be no need to test for it within any of those scripts as it will have already triggered before the scripts finish loading.


    Quote Originally Posted by Pullo View Post
    You could argue that the Rails guys did something wrong by including the file there, or perhaps they have a use case that I didn't think about, or then again maybe I am meant to configure something somewhere, so that the file is positioned before the </body> tag.
    Any script that is intended to interact with the content of the current page where the page is required to load first ought to go just before the </body> tag.

    I know of exactly two scripts that need to go in the head - one is where the script is testing whether to allow the cuurrent page to load or redirect and the other is where you want to add classes to the <html> tag so that the CSS can style the page differently depending on what JavaScript commands the browser supports.

    So I would argue that the Rails app in that instance is inserting the application.js in the wrong place in the HTML. If the app needs to cater for the rare case of a script that needs to go in the head then there should be two scripts for adding the code to so that it can all be inserted in the right place.

    Alternatively they could have just included the following script in the head without providing for any additional code being added as this is just about the only JavaScript that ever needs to go in the head and it isn't going to hurt to include it in every page:

    Code:
    if (top.location != self.location) top.location = self.location;
    document.getElementsByTagName('html')[0].class += ' js';
    Stephen J Chapman

    javascriptexample.net, Book Reviews, follow me on Twitter
    HTML Help, CSS Help, JavaScript Help, PHP/mySQL Help, blog
    <input name="html5" type="text" required pattern="^$">

  10. #10
    Community Advisor bronze trophy
    fretburner's Avatar
    Join Date
    Apr 2013
    Location
    Brazil
    Posts
    1,388
    Mentioned
    45 Post(s)
    Tagged
    12 Thread(s)
    Quote Originally Posted by felgall View Post
    What difference does loading JavaScript asynchronously make? Since the DOM is already loaded by the time the script to start the asynchronous load is called just before the </body> tag there should be no need to test for it within any of those scripts as it will have already triggered before the scripts finish loading.
    Because they load the scripts in tandem with the document, and so may finish loading before the DOM is ready.

  11. #11
    Programming Since 1978 silver trophybronze trophy felgall's Avatar
    Join Date
    Sep 2005
    Location
    Sydney, NSW, Australia
    Posts
    16,786
    Mentioned
    25 Post(s)
    Tagged
    1 Thread(s)
    Quote Originally Posted by fretburner View Post
    Because they load the scripts in tandem with the document, and so may finish loading before the DOM is ready.
    In which case the script will not be attached just before the </body> tag as if it were then it would have to finishg downloading before it started downloading in order to be able to run before the DOM had finished loading (which with that script placement has already occurred)..
    Stephen J Chapman

    javascriptexample.net, Book Reviews, follow me on Twitter
    HTML Help, CSS Help, JavaScript Help, PHP/mySQL Help, blog
    <input name="html5" type="text" required pattern="^$">

  12. #12
    Community Advisor bronze trophy
    fretburner's Avatar
    Join Date
    Apr 2013
    Location
    Brazil
    Posts
    1,388
    Mentioned
    45 Post(s)
    Tagged
    12 Thread(s)
    Quote Originally Posted by felgall View Post
    In which case the script will not be attached just before the </body> tag as if it were then it would have to finishg downloading before it started downloading in order to be able to run before the DOM had finished loading (which with that script placement has already occurred)..
    I think you're missing the point.

    The main reason it became best-practice to attach scripts at the end of the document is because they block the loading of anything that comes after them until they've been loaded. One of the functions of a script loader is to work around this problem, so scripts can be loaded alongside the document which is beneficial for JS-based apps.

    The side-effect is, of course, that with a loader you can't be sure that the document is ready. This is an important enough use-case that loaders such as Require.js provide a DOM-ready plugin to cater for this:
    It is possible when using RequireJS to load scripts quickly enough that they complete before the DOM is ready. Any work that tries to interact with the DOM should wait for the DOM to be ready.
    The BBC's developer guide explicitly states the need for the document ready method when using jquery in conjunction with Require.js:
    You can use jQuery by enabling RequireJS in your application, and using the standard require() method. Require does not wait for the page to finish loading, so you should also use one of the jQuery methods for ensuring the DOM is ready.
    You only need to browse through the blogs of a couple of prominent figures in the JS community to see that Require.js is becoming something of a standard for developing JS web apps, so I think it's an important enough use-case to make people aware of.

    As a general rule, sure, your advice about putting the scripts before </body> and not needing document ready callbacks is good practice and something I also recommend to people, but I see little point in being dogmatic and asserting that they are never needed.

  13. #13
    Programming Since 1978 silver trophybronze trophy felgall's Avatar
    Join Date
    Sep 2005
    Location
    Sydney, NSW, Australia
    Posts
    16,786
    Mentioned
    25 Post(s)
    Tagged
    1 Thread(s)
    Quote Originally Posted by fretburner View Post
    As a general rule, sure, your advice about putting the scripts before </body> and not needing document ready callbacks is good practice and something I also recommend to people, but I see little point in being dogmatic and asserting that they are never needed.
    I said they are never needed when you place the script before the </body> tag. I also said that with a couple of specific exceptions that all scripts can be placed at that point.

    I never said that you can't place the scripts earlier in the page (in which case as you say those tests then become necessary). Of course even if you then set the scripts to load alongside the rest of the page you still delay the visible portion of the page loading for anyone using a slow connection.

    Also the blocking that JavaScript does if you don't make the call asynchronous (either by loading the JavaScript from within another script or by adding an async attribute to the script tag) is of the rendering of the HTML, the files still download alongside each other in modern browsers, its just the display of the page that gets blocked until the script finishes loading in case it contains antiquated document.write statements. It is only really old browsers that actually blocked the downloading of the other files until the script finished. The only actual effect you can achieve by loading the scripts via JavaScript calls instead of embedding script tags in the HTML is that scripts downloaded that way are not included in the limit of files that HTML can download so if the browser can download 8 files referenced from the HTML then you can download as many scripts alongside that by adding the script tags from JavaScript. Of course if you do that in the head of the page then the scripts have to be added to the head as well since the DOM for the body of the page hasn't loaded yet. The faster download speeds and higher file limits make it less worthwhile to make your script more complicated to do the async download than it was for earleir browsers - it was a far more useful technique for IE5 than it is for IE10.
    Stephen J Chapman

    javascriptexample.net, Book Reviews, follow me on Twitter
    HTML Help, CSS Help, JavaScript Help, PHP/mySQL Help, blog
    <input name="html5" type="text" required pattern="^$">

  14. #14
    SitePoint Wizard bronze trophy Jeff Mott's Avatar
    Join Date
    Jul 2009
    Posts
    1,246
    Mentioned
    16 Post(s)
    Tagged
    0 Thread(s)
    Despite all the back and forth, it seems like everyone's been on the same page the whole time. We all agree that it's best to put JS just before the </body>, except in only a couple special circumstances (aka, "almost always"). One of those special circumstances includes using a loader, because loaders are generally put in the <head>.
    "First make it work. Then make it better."


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •