5

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'.

Joe
  • 16,328
  • 12
  • 61
  • 75
  • 1
    Just make sure that the element is "display: none" when you add its content. – Pointy Dec 06 '11 at 22:24
  • The only thing you need to worry about here is whether `$('#question')` is in the DOM when this code is ran. I'd say run this and then ask if it has issues. – gen_Eric Dec 06 '11 at 22:25
  • 2
    The wording of your questions is confusing. *"...am I guaranteed to have code like this..."* and *"Is it OK to know that there won't be any artifacts..."* Are you asking if the content will be seen before the dialog appears? It doesn't seem like you're asking about DOM ready issues. Are you? – RightSaidFred Dec 06 '11 at 22:30
  • @RightSaidFred yeah, I'm wondering whether the content will be seen right before the dialog appears. – Joe Dec 06 '11 at 22:39
  • @RightSaidFred just edited the question. Is it more clear? – Joe Dec 06 '11 at 22:48
  • @Joe Yes, the question is clear now. – Chris Shouts Dec 06 '11 at 22:56
  • 2
    @Joe: Yes your update was very helpful. Thanks. :) – RightSaidFred Dec 06 '11 at 23:01
  • @Joe: What does the plugin do? I'd probably try to apply the plugin to the new content *before* the content is added to the DOM. Like: `var content = $(data); content.doPluginStuff(); $('#question').hide().append(content).dialog(...);` Don't know if your plugin will like that, but maybe worth a try. – RightSaidFred Dec 06 '11 at 23:05
  • @RightSaidFred It's bxSlider and I'm sure there's a way to do it. It's also within an AJAX callback, making it slightly trickier. But the problem got me thinking about how the browser works with JS and what guarantees there are. So I'm still very interested in the answer. – Joe Dec 07 '11 at 20:07
  • @Joe: The only answer I could give would be *it depends*. A browser generally doesn't redraw until your script is complete, *but* if any of the code running is *asynchronous*, that will give the browser a chance to redraw, and the inserted content could be visible. – RightSaidFred Dec 07 '11 at 20:12
  • @RightSaidFred I think you're right. I still wonder if there's an official proposal somewhere for one or the other. It reminds me of Windows (`WM_`, etc) programming, in that they tried to make it as easy as possible by using a single, interleaving thread. And it was easy. If you really only used one thread. Rather, this thread affinity bit everybody when multithreading became mainstream. I do hope that a JS someday allows for background threads that can update its part of the DOM. But I also don't want to use some form of double-buffering in order to keep rendering artifacts away. – Joe Dec 07 '11 at 20:53

4 Answers4

1

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;
});
Chris Shouts
  • 5,377
  • 2
  • 29
  • 40
  • As long as synchronous JavaScript is executing, the browser typically doesn't redraw, so depending on what the plugin does, the user may not see the temporary content. – RightSaidFred Dec 06 '11 at 23:03
0

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( ... );
  });
});
gen_Eric
  • 223,194
  • 41
  • 299
  • 337
mattacular
  • 1,849
  • 13
  • 17
  • This is actually happening within a click event. I'll update the question. – Joe Dec 06 '11 at 22:38
  • 3
    -1, Not *all* DOM-related activity should be done after the document is ready. Read [this post](https://groups.google.com/group/closure-library-discuss/browse_thread/thread/1beecbb5d6afcb41?pli=1) by Erik Arvidsson (a Google Closure developer). – David Murdoch Dec 06 '11 at 22:57
0

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/

Community
  • 1
  • 1
JesseBuesking
  • 6,496
  • 4
  • 44
  • 89
0

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.

austincheney
  • 1,097
  • 7
  • 8