【问题标题】:Ajax requests ASAP right before </body>, or on document ready too?Ajax 在 </body> 之前尽快请求,还是在文档准备好之前?
【发布时间】:2012-11-18 02:19:37
【问题描述】:

我正在优化一个页面,但我无法区分这些结果之间的差异(第一个显然更快,但我不确定它是否会减慢页面的渲染速度或其他什么):

这个会尽快启动请求,并在文档就绪时修改 DOM:

<script>
$.ajax({
    url: '/some-url',
    success: function() {
        $(document).ready(function() {
            // do something
        });
    }
});
</script>
</body>

这将在文档准备好时开始请求:

<script>
$(document).ready(function() {
    $.ajax({
        url: '/some-url',
        success: function() {
            // do something
        }
    });
});
</script>
</body>

推荐哪一个?

【问题讨论】:

  • @whirlwin 我已经在这两种情况下都这样做了。或者你的意思是关闭标签后?
  • 不,你已经在做我试图解释的事情了。
  • 如果您等待文档成功准备就绪,由于 JavaScript 的单线程特性,这是否可能会停止页面渲染直到成功完成?
  • @FrançoisWahl 不,页面不会“等待”它准备好。在success 中,他们会将一个新的“就绪”事件绑定到文档。如果在success 执行时文档已经准备好,则$(document).ready 的函数将不会执行。
  • @Ian:那是错误的。 jQuery.fn.ready总是触发,即使 DOM 之前已经准备好。

标签: javascript jquery ajax optimization


【解决方案1】:

这里的最佳实践是尽快启动 Ajax 请求,但只有在文档准备好时才开始修改 DOM (DOMContentLoaded)。为此,您可以使用与 jQuerys 扩展的 jXHR 对象连接的 jQuerys Deferred objects

<script>
    var req      = $.ajax({}),
        docReady = jQuery.Deferred();

    $(function() {
        docReady.resolve();
    });

    $.when( req, docReady ).done(function( data ) {
        // read the returned data and modify the DOM
    });
</script>

在 DOM 准备好之前等待开始请求是浪费时间。 XHR 请求对 DOM 发生的事情没有任何业务和兴趣。


将这两件事完全解耦更有意义。如果由于某种原因 DOM 需要很长时间才能准备好,您不会浪费时间让 HTTP 请求 运行并收集其数据。反过来,如果 request 很慢,你也会浪费时间。所以你现在的 sn-ps 就像

DOM ready    
           -> XHR request    
                          -> Do something useful

而我的例子是这样的

DOM ready    
XHR request
            -> Do something useful as soon as the DOM and request are ready

【讨论】:

  • 这和我的第一个例子一样吗?我不知道 when(req).done(),它看起来“更正确”。
  • @ChocoDeveloper:嗯,它有点接近您的第一个示例,但正如您正确提到的,我的示例在方便性方面更正确。它几乎同时启动请求和 DOMContentReady 的侦听器,但是当 ready 事件 触发并且请求尚未完成时,它仍然会“等待”(小心,它只是一个回调),直到请求成功完成。
  • jAndy 和您的代码有两个不同之处。第一个是你在&lt;/body&gt; 之前有你的电话,所以你的$.ajax 电话开始时间很晚(意味着它会很晚才结束)。第二个区别是 jAndy 的代码使用了更多的 jQuery 方法来确定 DOM 何时准备好以及 AJAX 调用是否成功,并且可能会导致 success 方法运行时的更多延迟(在不太可能的情况下 AJAX 请求完成在所有绑定完成之前)。我认为尽快将您的第一个示例放在您的页面上是最好的解决方案
  • 我仍然看不出有什么不同。在我的第一个示例中,我没有等待文档准备好启动 ajax 请求。文档就绪部分发生在我传递给 ajax() 的回调中。它成功了,因为就像你说的那样,如果在我进行绑定时文档已经准备好,则执行回调。
  • @jAndy 新代码很简洁,但与 OP 的第一个版本并没有太大区别。在第一个 sn-p 中,只有成功函数(相当于 done())绑定到 DOM 就绪,而不是 XHR 请求本身,这与您的回答相反。
【解决方案2】:

由于$.ajax 不以任何方式依赖于DOM,你没有理由不能尽快调用它。在这种情况下,我会将它放在&lt;head&gt; 部分中,并在其依赖的脚本/脚本文件完成后立即调用它(至少是 jQuery 库)。更快地触发 AJAX 请求意味着响应能够更快地返回 - 实际情况可能并非如此,但这并不重要。

检查以确保 DOM 在 success 内准备就绪对您来说是必要的,这是执行代码的最快方式。使用 $.when( req ).done(function () {}) 会创建另外 2 个 jQuery 方法调用,这可能会或可能不会显着延迟 success 代码的执行 - 它会延迟它,但可能微不足道。

此外,您在 success 方法中使用 document.ready 的示例创建了 DOM 已准备好并可以立即执行的 可能性(如果 AJAX 请求在 DOM 之前完成)已满载,这是我没想到的)。在 jAndy 的示例中,document.ready$.ajax 之后立即运行,它保证它将为准备好的文档绑定一个事件处理程序......这意味着它必须被存储(导致 DOM稍后准备好),然后在事件发生后查找并执行。同样,区别在于 可能性保证...而且一切都可能微不足道(只要您不使用第二个示例)。

【讨论】:

  • 你是否 100% 确定在 body 结束前执行某些事情是可以的?我知道我只是在做绑定,但我认为这是一个不费吹灰之力的黄金法则。
  • @ChocoDeveloper 我不确定我是否理解。您是在问是否可以在 &lt;/body&gt; 之前的任何地方运行 Javascript?我相信,Javascript 可以在头部和身体的任何地方运行。但是当然,一个 DOM 元素在它准备好之前是不能被操作的(在页面上被解析之后)。将内容放在正文的末尾是一种确保正文中的所有元素都准备就绪并将所有 Javascript 代码放在一起的组织方式。
  • 是的,我一直读到,为了优化(不仅仅是组织),你必须把所有的 js 放在
【解决方案3】:

在这个简单的例子中,两个版本都可以。哪个更好取决于您的页面和其他脚本。 如果您的脚本稍微复杂一些,并且您需要将数据传递给必须从页面获取的 ajax-request,而您的页面此时尚未准备好 - 您将遇到错误。

另一件事是,您页面上的任何脚本都会在处理它时阻止浏览器,因此更复杂的代码没有 doc-ready 可能会导致页面呈现过程中的短暂停止。 在大多数情况下,我更喜欢让浏览器加载所有 HTML、CSS 和 JS - 然后开始我的渐进增强和加载附加内容。

但同样——在这个简单的例子中——我看不出有什么不同。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多