Joe
Joe

Reputation: 16831

Does browser rendering and JavaScript execution happen simultaneously?

For example, if I have this:

$('#button').click(function() {
    $.get('/question', function(data) {
        $('#question').html(data);
        $('#question').dialog( ... );
    });
    return false;
});

Will the user see the question content for a brief moment before the dialog is shown?

Note: Normally I'd just hide the #question manually, but there's actually a step in between html() and dialog() with another jQuery plugin where the content must not be 'hidden'.

Upvotes: 5

Views: 342

Answers (4)

mattacular
mattacular

Reputation: 1889

This is the reason initializing any DOM-related activity should be done/triggered from within $(document).ready() .

So if you put you $.get statement inside of doc ready, you can ensure that all the elements in the HTML have been rendered and are ready to be interacted with via JS.

$(document).ready(function () {
  $.get('/question', function(data) {
    $('#question').html(data);
    $('#question').dialog( ... );
  });
});

Upvotes: 0

austincheney
austincheney

Reputation: 1115

In your case absolute not, because you are using a framework. It works like this:

1) Script code is requested from external files as the page progressively loads. An HTML parser has to parse the script tags before there is any awareness of a script request. This code executes when called, but it is fed into the JavaScript interpreter the moment it is available to the JavaScript interpreter.

2) Script code resident directly in the page is fed into the interpreter as the HTML code is parsed by an HTML parser and a script tag is encountered. Code inside functions executes when called, with one exception. Otherwise code executes immediately upon interpretation. The one exception is when a function block is immediately followed by "()" which indicates immediate invocation.

3) Most code that executes initially executes from function calls made with the "onload" event. The onload event occurs when the static DOM is fully available from the HTML parser and when all asset requests from the initial static HTML are requested. In some edge cases with older browsers it is possible for conflicting conditions to occur that create a race condition in the page that prevents the onload event from ever firing or after an extraordinary delay.

4) You are using jQuery, so you are at a severe disadvantage with regards to speed of availability. jQuery code is JavaScript code, so it has to enter the JavaScript interpreter exactly like any other JavaScript. All the prior points from this post must be observed before any jQuery code can execute.

5) When I perform A/B testing I need code to execute as absolutely as early as possible and as fast as possible to minimize flicker on the page, so frameworks are definitely not an option. In this case I follow these steps:

5a) I find the first id attribute directly after the DOM node(s) that I need to access. 5b) I write a function to test for the availability of this node. If the node is available then the areas above it are available, so I am know I am solid. Consider the following example:

    var test = function () {
        var a = document.getElementById("first_node_lower_than_I_need");
        if (a !== null && typeof a === "object") {
            //my code here, because I know my target area is available
        } else {
            setTimeout(test, 100);
        }
    };
    setTimeout(test, 100);

5c) Notice in the sample code above that I call my function with a setTimout delay to give the DOM a fighting chance. If the function executes early that is okay because I am calling it recursively with a delay to give the DOM some extra time to load. If you set your delay to 50ms or lower you are increasing execution time in IE8 and lower because of numerous unnecessary calls for the function. I recommend keeping the delay at 100ms for an ideal balance cross browser, but if you really want rapid execution in new browsers then set the first delay to 50ms, this is the one outside the function, and keep the other at 100ms.

5d) Minimize your use of innerHTML property with the above method, or be very familiar with the targeted page to know when it is okay to use innerHTML. The problem with innerHTML is that it changes the page output without reporting those changes back to the parsed DOM in memory, which normally is an irrelevant disconnect. However, in this case it is certainly relevant because of how fast and early your injected code can execute. This is a problem because other code that executes later, such as with the onload event or jQuery's ready event, will either overwrite your changes or will not be able to find their respected DOM load and simply drop their execution all together. This is particularly an important concern if you are targeted a very high level node in the DOM tree, so for your safety be very specific when selecting nodes to use innerHTML or just use DOM methods. This is a bit more complicated in that you cannot use a DOM method only solution because you cannot change text nodes with the nodeValue method cross-browser as this is not supported in IE7.

If you need to execute JavaScript code before completion of DOM parsing then do not use a JavaScript framework. Write using plain regular JavaScript code and optimize the hell out of it. Otherwise you will always have flicker and the larger of the static HTML download the longer and more noticeable that flicker will be. Additionally, jQuery code tends be far slower to execute than regular optimized JavaScript due to its reliance on CSS like selectors. If your injected jQuery code is required to perform a large task on a very large static HTML document then it is unlikely to complete execution in IE7 without timing out.

Upvotes: 0

Chris Shouts
Chris Shouts

Reputation: 5427

Short Answer

Yes, it's possible that the user will see the question content for a brief moment before the dialog is shown.

The Fix

To guarantee you won't momentarily see the contents of #question before displaying the dialog, absolutely position #question offscreen before displaying it. After that, call the jQuery plugin that requires #question to be displayed. Finally, hide #question and restore its position.

CSS

#question
{
    display: none;
}

JavaScript

$('#button').click(function() {
  $.get('/question', function(data) {
    var question = $('#question');
    question.html(data);
    var position = question.css('position');
    var top = question.css('top');
    var left = question.css('left');
    question.css({ position: 'absolute', top: -1000, left: -1000 }).show();
    //whatever you need to do with #question while it's not hidden
    question.hide().css({ position: position, top: top, left: left });
    question.dialog( ... );
  });
  return false;
});

Upvotes: 1

JesseBuesking
JesseBuesking

Reputation: 6586

The browser will render the DOM up until that call, at which point it will stop and parse/execute your js. This is why it's considered best practice to put all script tags at the bottom of a page (so that the browser can render enough of the DOM so your visitors aren't stuck staring at a blank white screen).

Using

$(document).ready();

can alleviate this to an extent, but if you're truly concerned with when it is added to the DOM, make sure your code is added at the very bottom of your HTML's body tag.

References:

http://developer.yahoo.com/blogs/ydn/posts/2007/07/high_performanc_5/

Upvotes: 0

Related Questions