浏览器渲染和JavaScript执行是否同时发生?

5
例如,如果我有这样一个东西:
$('#button').click(function() {
    $.get('/question', function(data) {
        $('#question').html(data);
        $('#question').dialog( ... );
    });
    return false;
});

在显示对话框之前,用户是否会短暂地看到问题内容?

注意:通常情况下我会手动隐藏#question,但实际上在html()dialog()之间还有另一个jQuery插件需要处理,因此内容不能被“隐藏”。


1
只需确保在添加内容时,该元素的"display: none"。 - Pointy
你需要担心的唯一问题是当代码运行时,$('#question')是否在DOM中。我建议先运行此代码,然后再询问是否有问题。 - gen_Eric
2
你的问题措辞有点让人困惑。“... 我是否保证会有这样的代码...” 和 “知道不会有任何副作用是可以的吗?” 你是在问内容是否会在对话框出现之前被看到吗?这似乎不像你在询问 DOM 就绪问题。你是吗? - RightSaidFred
@RightSaidFred 刚刚编辑了这个问题。现在更清楚了吗? - Joe
2
@Joe:是的,你的更新非常有帮助。谢谢。 :) - RightSaidFred
显示剩余6条评论
4个回答

1

简短回答

是的,用户在显示对话框之前可能会短暂地看到问题内容。

解决方法

为了确保在显示对话框之前不会短暂地看到#question的内容,请将其绝对定位到屏幕外。然后,调用需要显示#question的jQuery插件。最后,隐藏#question并恢复其位置。

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;
});

只要同步JavaScript在执行,通常浏览器不会重新绘制,所以根据插件的功能,用户可能看不到临时内容。 - RightSaidFred

0
浏览器会渲染DOM直到该调用,此时它将停止并解析/执行您的js。这就是为什么将所有脚本标签放在页面底部被认为是最佳实践的原因(这样浏览器可以渲染足够的DOM,以便您的访问者不会被困在空白屏幕上盯着看)。
使用
$(document).ready();

可以在一定程度上缓解这个问题,但如果你真的关心它何时添加到DOM中,请确保你的代码添加在HTML的body标签的最底部。

参考资料:

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


0

这就是为什么初始化任何基于DOM的操作都应该在 $(document).ready() 中完成或触发。

所以,如果你把你的 $.get 语句放在 doc ready 内部,你可以确保 HTML 中的所有元素都已被渲染,并且可以通过JS进行交互。

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

这实际上是在单击事件中发生的。我会更新问题。 - Joe
3
并不是所有与DOM相关的操作都应该在文档准备好之后进行。请阅读谷歌Closure开发者Erik Arvidsson的这篇帖子。 - David Murdoch

0
在您的情况下,绝对不是这样的,因为您正在使用框架。它的工作方式如下:
1)随着页面逐步加载,从外部文件请求脚本代码。在 script 标签被解析之前,HTML 解析器必须解析脚本标签。当调用此代码时,它会执行,但一旦它可供 JavaScript 解释器使用,它就会被馈送到 JavaScript 解释器中。
2)直接驻留在页面中的脚本代码将随着 HTML 代码由 HTML 解析器解析并遇到脚本标记而被馈送到解释器中。函数内部的代码在调用时执行,除了一个例外。否则,代码会立即执行解释。唯一的例外是当函数块紧随其后跟随“()”时,表示立即调用。
3)大多数最初执行的代码都是通过“onload”事件进行函数调用。当静态 DOM 从 HTML 解析器完全可用且初始静态 HTML 的所有资产请求都已请求时,onload 事件发生。在某些边缘情况下,旧版浏览器可能会出现冲突条件,从而在页面中创建竞争条件,导致 onload 事件永远无法触发或延迟非常长。

4) 你正在使用jQuery,因此在可用性方面处于严重劣势。 jQuery代码是JavaScript代码,因此它必须像任何其他JavaScript一样进入JavaScript解释器。 在任何jQuery代码执行之前,必须遵守本帖子中的所有先前点。

5) 当我执行A / B测试时,我需要尽可能早地执行代码并尽可能快地执行,以最小化页面上的闪烁,因此框架绝对不是一个选项。 在这种情况下,我遵循以下步骤:

5a)我查找所需访问的DOM节点后直接找到第一个id属性。 5b)我编写一个函数来测试此节点的可用性。 如果该节点可用,则其上方区域也可用,因此我知道我是稳定的。 请考虑以下示例:

    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) 注意在上面的示例代码中,我使用setTimout延迟调用我的函数,以便DOM有更多的时间加载。如果函数提前执行,那没关系,因为我会递归地调用它并设置延迟,以给DOM一些额外的加载时间。如果您将延迟设置为50ms或更低,则由于对函数的大量不必要调用,会增加IE8及以下版本的执行时间。我建议将延迟保持在100ms,以实现跨浏览器的理想平衡,但如果您真的想在新浏览器中实现快速执行,则将第一个延迟设置为50ms(这是函数外部的延迟),并将另一个延迟保持在100ms。

5d) 最小化使用innerHTML属性,或者非常熟悉目标页面,知道何时可以使用innerHTML。 innerHTML的问题在于它会更改页面输出,而不将这些更改报告回内存中解析的DOM,这通常是一个无关紧要的断开连接。然而,在这种情况下,由于您注入的代码可以快速且早期地执行,因此这显然是相关的。这是一个问题,因为稍后执行的其他代码(例如onload事件或jQuery的ready事件)将覆盖您的更改,或者根本找不到其受尊重的DOM加载并完全放弃执行。如果您针对DOM树中的非常高级节点,则特别需要注意此问题,因此为了安全起见,请在选择要使用innerHTML的节点时非常具体,或者只使用DOM方法。这有点复杂,因为您不能仅使用DOM方法解决问题,因为在跨浏览器中,您无法使用nodeValue方法更改文本节点,因为IE7不支持此方法。
如果您需要在DOM解析完成之前执行JavaScript代码,则不要使用JavaScript框架。请使用普通的JavaScript代码编写,并对其进行优化。否则,您将始终会出现闪烁问题,静态HTML下载越大,闪烁时间就越长,也越明显。此外,由于jQuery依赖于类似CSS的选择器,因此jQuery代码往往比常规优化的JavaScript执行速度慢得多。如果您注入的jQuery代码需要在非常大的静态HTML文档上执行大量任务,则在IE7中完成执行的可能性很小。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接