【问题标题】:When do browsers start to render partially transmitted HTML?浏览器何时开始呈现部分传输的 HTML?
【发布时间】:2011-01-13 07:25:38
【问题描述】:

我有一个长期运行的报告,并希望在生成时向用户显示等待微调器。我已经完成了这项工作,但不确定我做得最好还是正确。

这是使用 ColdFusion,但我猜它可能是任何语言。在页面顶部,我有一些显示等待微调器的 Javascript (jQuery),还有一个 documentReady 处理程序,我在其中将微调器取下来。我刷新输出(如果重要),然后其余代码处理报告内容。这从来没有渲染微调器,我推测,即使我正在刷新服务器上的东西,也会发生一些缓冲,并且浏览器直到为时已晚才看到微调器代码。所以,我在刷新之前添加了一个循环,吐出几百行 HTML cmets。在微调了行数之后,就成功了。我当时认为其他网站也是如此。

但是:今天,当我看到我的另一个页面逐行吐出一个长时间运行的作业的状态时,我突然想到,该页面在每一行之后都会刷新,并且浏览器会根据需要逐步呈现。这与我上面的结论不符,现在我不知道规则是什么。有没有可预测的方法来做到这一点?是否因浏览器而异?

澄清:我很欣赏试图解释执行等待微调器的正确方法的答案,但我只是使用等待微调器作为示例来说明我的真正问题:是否有可靠的方法来预测浏览器何时会开始渲染 HTML,因为它通过网络流式传输给他们?通过观察很明显,浏览器不会等待 /html 标签开始工作。这个问题不一定与Javascript有关。例如,我描述的显示状态的第二个页面是纯 HTML。

【问题讨论】:

  • 如果我理解正确,您是在文档就绪事件触发之前使用 jQuery 将微调器加载到 DOM 中?我不知道这是否与您的问题有关,但这不是您想要做的。这是您正在进行的ajax调用吗?听起来您正在尝试执行类似 AJAX 的功能(使用等待指示器加载 DOM,进行 AJAX 调用以加载报告,在加载时将等待指示器替换为报告),但不使用 AJAX。
  • 没有 AJAX 调用。有简单的内联 jQuery 来显示微调器。该页面的其余部分是实际的报告数据。这工作正常。为什么这不是我想做的?如果我可以让它工作,那么将页面分成两部分似乎要简单得多 - 初始位加上通过 AJAX 返回的报告。

标签: jquery html browser spinner flush


【解决方案1】:

我希望它会因浏览器而异:有些会在页面完全接收之前开始呈现;其他人将在开始之前等待整个 html 文件。

我注意到 HTTP 响应规范提供了一个“206 Partial Content”标头,这可能为值得研究的跨浏览器解决方案带来一些希望。

几乎可以肯定有很多方法可以削减它,但我的直接想法是交付存根页面,然后使用 ajax 按需拉取和呈现片段。例如,许多大型网站最初似乎提供了一个最小视图,然后如果您向下滚动足够多,它会触发一个 ajax 请求以检索更多数据并将其附加到页面。例如:facebook、slashdot。

我无法想象这太难实现了;即使是冷聚变。在触发 ajax 请求时启动微调器,并在调用回调时停止它。

【讨论】:

  • 对于后人:关于206 Partial Content 的推测是不准确的。此响应代码只能用于回复 HTTP 范围请求,即对部分资源的请求,例如在音频/视频流中搜索或恢复下载。
【解决方案2】:

--- 澄清后回答---

我的原始答案应该对某人有用(我希望),但这不是对问题的直接回应,所以我会发布另一个答案

您重申的问题的答案是“否”。在 FF 的情况下,有一个预定义的初始渲染延迟,但其他浏览器会有所不同。 FF 渲染延迟也可以调整。

以 FF 为例,最初的 250 毫秒是 FF 在尝试第一次渲染之前找出至少一些有用信息的时间。然后,它会在了解更多信息后定期进行额外的渲染。

您无法确定浏览器何时开始呈现 HTML 文档。

--- 原始答案---

为了直接回答您的问题,我相信 Firefox 会等待 250 毫秒,然后才会对收到的第一个数据采取行动,但这可以更改。对于其他浏览器,我不知道。

但是,你不想走那条路。

当 jQuery 准备好发挥它的魔力时,它会通过触发 $(document).ready() 来通知您。在此之前,任何使用 jQuery 的尝试都会失败。换句话说,您的微调器没有显示,因为 jQuery 还没有准备好处理该请求。

考虑以下示例,其中两个占位符显示在屏幕上,我们将使用 jQuery 将它们隐藏。

<html>
    <head>
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js"></script>
        <script>

            // We're not ready yet.  This will fail.
            $(".placeholder").hide();

            $(document).ready(function(){
                // This won't fail
                $("#one").hide();
            });

        </script>
    </head>
    <body>
        <div id="one" class="placeholder">Placeholder One</div>
        <div id="two" class="placeholder">Placeholder Two</div>
    </body>
</html>

乍一看$("#one").hide(); 可能是多余的,但事实并非如此。 $(".placeholder").hide(); 在 jQuery 准备好之前被调用,所以它没有任何效果,这就是为什么如果你在 Web 浏览器中运行上面的标记,你会看到显示“占位符二”(而不是“占位符一”)。

既然我们已经解决了这个问题,那么解决更大问题(“正确方法”)的方法就是 AJAX。

  1. 加载包含微调器代码的基本页面。确保加载微调器的代码作为$(document).ready() 的一部分运行。
  2. 使用jQuery's AJAX functionality 获取您想要的报告。
  3. 当它返回时,隐藏微调器,将报表注入到您的基本页面中。

祝你好运!

【讨论】:

  • E-man - 你从哪里得到 250ms 的数字?你是第二个说我正在做的事情不是我想做的事情的人。好的,但是为什么呢?它不可靠吗?这是一个内部应用程序,需要使用 FF,所以我不担心其他浏览器(但也想知道)。我知道 AJAX 方法,但试图避免额外的复杂性。关于您的示例-我认为您是在说初始 hide() 不起作用,因为 jQuery 尚未准备好,但我当前的代码工作正常,并且通过在 document.ready 触发之前调用 jQuery 来实现。我错过了什么吗?
  • 对于 250 毫秒 hackaday.com/2004/12/26/speed-up-firefox 在 $(document).ready() 触发之前你不能使用 jQuery——我认为你的评论循环是在强制一个“好的,有些事情已经停止了,让我们采取我们的FF 中的“暂时”情况(最佳猜测)。这不正常,我很确定。我将在另一个答案中回答重述的问题。
  • 在调用.ready() 之前不能使用jQuery,这是错误的。您不能保证在.ready() 触发之前进行调用时文档中的每个元素都可用,但可能存在许多元素。特别是,如果您在 HTML 正文中放置一个脚本标记,那么即使 .ready() 尚未触发,脚本标记之前的所有元素都可以安全使用。
  • 举一个@jfriend00评论的具体例子:如果该脚本块被移动到带有类占位符的div之后,它们将按预期隐藏。这就是为什么早在 jQuery 流行之前,建议是“将你的脚本移动到正文块的末尾”。 OTOH,我不建议使用这种旧方法:如果您的 javascript 减慢了初始页面加载速度,请使用defer 标记有问题的脚本标记,或者将任何 JS 函数执行移至“$...ready”,或者,如果不使用 jQuery,则在 DOMContentLoaded 事件监听器中。
  • ... 在这个问题的上下文中,我说的 “如果您的 javascript 正在减慢初始页面加载速度” 是不相关的。我的观点是简单地“将脚本移动到页面底部”,可能已经解决了这个问题。但是现在,为了确保您的脚本不会减慢初始页面加载速度,最好使用我提到的三种技术之一。
【解决方案3】:

如果我理解正确,您希望在页面仍在加载内容时显示“正在加载”图像。

我所做的,我认为最好的方法是在页面顶部添加一个 div-tag,最接近包含加载图像/文本的 body-tag。您可以借助一些 css 将此 div 放置在其他地方。

然后让 Jquery 在页面加载时删除这个 div。而不是像一些人推荐的那样使用 $(document).ready 我会使用 $(window).load 代替,因为它在整个页面完全加载时被激活,包括所有框架、对象和图像。
此处链接; http://4loc.wordpress.com/2009/04/28/documentready-vs-windowload/

示例;

<body>    
<div id="loading" style="z-index:200; width:100%; height:40px; border-top:2px #D4D4D4 solid;  background:#E8E8E8; color:#000; position:fixed; bottom:0; left:0;">
    <div align="center">
        <img src="load.gif" alt="Loading...">
    </div>
</div>
<script type="text/javascript">
    $(window).load(function() { $("#loading").remove(); });
</script>
[...]

...

【讨论】:

    【解决方案4】:

    除了 Firefox 的内置延迟之外,还有其他方面会导致浏览器在渲染前等待。

    当一个 html 页面被发送到浏览器时,它首先必须决定事情的去向,然后才能绘制屏幕。例如,表格因导致渲染延迟而臭名昭著。为了绘制表格,浏览器需要计算列大小。如果您使用百分比作为列宽或根本不指定它们,则浏览器必须在呈现之前获取整个表格。

    但是,如果您使用类似table-layout: fixed; css 属性的东西,那么浏览器可以只读取第一行并在数据输入时开始绘制。

    其他标签可能会导致类似问题。基本上任何时候浏览器都必须计算内容的大小,然后它必须要呈现所有的内容。如果您可以通过使用固定大小(宽度/高度)的元素提前给它提示,那么浏览器不需要计算任何东西,它可以在下载元素时绘制它们。

    作为一个自我强加的规则,我从不让浏览器决定任何事情。相反,我给我的元素固定大小。因此,我工作的网站通常具有闪电般的渲染速度。

    【讨论】:

    • 带有 URL 的 CSS 样式标签也被阻止。与 JS 脚本标签一样,除非标记为 defer。在文件 before 给定 HTML 元素中声明的任何此类标记都必须在该元素尝试呈现之前下载和解析。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-14
    • 2015-10-03
    • 1970-01-01
    • 1970-01-01
    • 2018-09-04
    • 2023-03-30
    • 2018-03-24
    相关资源
    最近更新 更多