前端渐进式渲染_通过多次刷新进行渐进式渲染

前端渐进式渲染

前端渐进式渲染

2010 update: Lo, the Web Performance Advent Calendar hath moved

2010年更新: Lo, Web Performance Advent Calendar已移动

10/2011 update: You can also read the web page with Romanian translation (by Web Geek Science)

10/2011更新:您也可以阅读网页(用罗马尼亚语翻译网站野人科学)

Dec 21 This post is part of the 2009 performance advent calendar experiment. Stay tuned for the articles to come.

12月21日,该帖子是2009年效果降临日历实验的一部分。 请继续关注未来的文章。

Perceived page loading time is just as important as the real loading time. And when it comes to user perception, visible indication of progress is always good. The user gets feedback that something is going on (and in the right direction) and feels much better.

感知页面加载时间与实际加载时间一样重要。 当涉及到用户感知时,可见的进度指示始终是好的。 用户会收到有关正在进行的事情(方向正确)的反馈,感觉好多了。

Using multiple content flushes allows you to improve both the real and the perceived performance. Let's see how.

使用多个内容刷新可让您同时改善实际性能和感知性能。 让我们看看如何。

头冲洗() (The head flush())

While your server is busy stitching the HTML from different sources - web services, database, etc - the browser (and hence the user) just sits and waits. Why don't we make it work and start downloading components we know will be absolutely needed, such as the logo, the sprite, css, javascript... While the server is busy, you can send a part of the HTML, for example the whole <head> of the document. In there you can put the references to external components such as the CSS, which then the browser can head-start downloading while waiting for the whole HTML response.

当您的服务器忙于缝合来自不同来源(Web服务,数据库等)HTML时,浏览器(因此也就是用户)只是处于等待状态。 我们为什么不使它工作,并开始下载我们绝对需要的组件,例如徽标,sprite,css,javascript等。当服务器繁忙时,您可以发送一部分HTML,例如文件的整个<head> 。 您可以在其中放置对外部组件(例如CSS)的引用,然后浏览器可以在等待整个HTML响应的同时开始进行下载。

<html>
<head>
  <title>the page</title>
  <link rel=".." href="my.css" />
  <script src="my.js"></script>
</head>
<?php flush(); ?>
<body>
  ...

Doing something like this will result in shorter waterfalls, because more downloads can happen in parallel. In the waterfall below the page is not yet completed at 0.4 seconds, yet the browser has already requested more components.

这样做会缩短瀑布,因为可以并行进行更多下载。 页面下方的瀑布尚未在0.4秒后完成,但浏览器已请求更多组件。

更进一步-多次冲洗 (One step further - multiple flushes)

While having the browser busy is good and the whole page loads faster, can we do better? How about letting the user see something while the server is still busy? Remember - show something "in a blink of an eye". And how about doing the flushing several times, hence rendering the page is stages. This will help show usable partial versions of the page without waiting on potentially long-loading page or waiting some blocking JavaScripts to load.

虽然让浏览器忙碌是一件好事,整个页面加载速度更快,但是我们可以做得更好吗? 在服务器繁忙时让用户看到东西怎么样? 记住-在眨眼之间显示一些东西。 以及如何进行多次冲洗,从而呈现页面是一个阶段。 这将有助于显示页面的可用部分版本,而不必等待可能长时间加载的页面或等待某些阻止JavaScript加载。

Here's an example - Google search results.

这是一个示例-Google搜索结果。

The header part of that page (chunk #1) doesn't need any complicated logic. True, the page title and pre-filling the input box are dynamic parts, but this is just a simple echo of the user input, nothing that requires complex work. So out goes the header. Notice that the number of search results is not visible yet. In this chunk there's the logo, so the sprite is downloaded. If this page was using external CSS, it would be included in the head too.

该页面的标题部分(1号块)不需要任何复杂的逻辑。 的确,页面标题和输入框的预填充是动态的部分,但这只是用户输入的简单回显,不需要任何复杂的工作。 这样就可以了标题。 请注意,搜索结果的数量尚不可见。 在此块中有徽标,因此下载了精灵。 如果此页面使用的是外部CSS,它也将包含在头部中。

Then, the search results, the meat of the page. Out it goes, as a static HTML chunk #2.

然后,搜索结果,页面的内容。 它成为静态HTML块#2。

So far the page is done, but not quite yet. There's some progressive enhancement of the page which requires JavaScript. And JavaScript blocks. So include it in the footer as chunk #3.

到目前为止,页面已完成,但尚未完成。 该页面需要JavaScript的逐步增强。 和JavaScript块。 因此,将其作为页脚3包含在页脚中。

The page is usable even without the JavaScript and without the footer. The user mostly cares about the results, so chunk #2 is what matters most. Chunk #3 can even get lost in transfer. As for chunk #1 - it's just to give feedback that "hey, we're working on your query". The first chunk actually tricks the user to believe that the query is already done. "Heck", concludes the user seeing that the page is already coming up, "that was FAST" 🙂

即使没有JavaScript也没有页脚,该页面仍然可用。 用户主要关心结果,因此第2块是最重要的。 第3块甚至可能在传输中丢失。 至于第1块-只是为了提供反馈“嘿,我们正在处理您的查询”。 第一个块实际上使用户误以为该查询已经完成。 “哎呀”,断定用户看到页面已经快到了,“那是FAST”“

无聊的细节-HTTP 1.1分块编码 (Boring details - HTTP 1.1 chunked encoding)

So how does this work actually, how come the HTML is served in parts?

那么这实际上是如何工作的,HTML是如何部分提供的?

The answer is - HTTP 1.1 chunked encoding. A normal HTTP response looks like:

答案是-HTTP 1.1分块编码。 正常的HTTP响应如下所示:

Headers...
[One empty line]
<html><body>response...

A chunked response would be like:

分块的响应就像:

Headers...
Transfer-Encoding: chunked
More headers...

size of chunk #1
<html><body>...chunk #1...

size of chunk #2
...chunk #2...

size of chunk #3
...chunk #3 </body><html>

0 (meaning "the end!")

The chunk sizes are given as a hexadecimal. Here's an example response (from the wikipedia article)

块大小以十六进制形式给出。 这是一个示例响应(来自维基百科的文章)

HTTP/1.1 200 OK
Content-Type: text/plain
Transfer-Encoding: chunked

25
This is the data in the first chunk

1C
and this is the second one

0

分块/冲洗策略(Chunking/flushing strategies)

There's basically two paths you can take when it comes to chunking:

涉及分块时,基本上可以采取两种方法:

Application-level chunking 应用程序级分块
when your web app knows when to flush, based on some logic. The Google search above is an example of application-level flushing - header, body, footer are parts of the page, known to the web application
基于某些逻辑,何时您的Web应用知道何时刷新。 上面的Google搜索是应用程序级刷新的示例-标头,正文,页脚是页面的一部分,对于Web应用程序是已知的
Server-level chunking 服务器级分块
when your application doesn't worry about how the content is delivered, but leaves this task to the server. The server can choose some strategy for flushing, for example once every 4K of output. Google search does this when the user agent doesn't support gzip - it flushes out every 4k. Bing.com does it similarly - flushing about every 1k (sometimes 2K, sometimes less) regardless of the user agent's support for gzip. Interestingly enough bing's first chunk is often non-readable characters - just something that tells the browser - hey, I'm alive, here's your first byte
当您的应用程序不担心内容的交付方式,而将这项任务留给服务器时。 服务器可以选择某种刷新策略,例如每4K输出一次。 当用户代理不支持gzip时,Google搜索就会执行此操作-它每4k刷新一次。 Bing.com的操作与此类似-大约每1k(有时2k,有时更少)刷新一次,而不管用户代理对gzip的支持如何。 有趣的是,bing的第一个块通常是不可读的字符-只是告诉浏览器的字符-嘿,我还活着,这是您的第一个字节

Amazon is an interesting example of doing a mix of both strategies - it looks like sometimes it's server level (e.g. in the middle of an html tag) but sometimes it looks like the chunk contains (or wraps up) a page section. Amazon is also a good example of focusing on what's important on a page (Why is the user here? What do they want? What do we want them to do?) and making sure it's rendered first.

亚马逊是将两种策略混合使用的一个有趣示例-看起来有时是服务器级别的(例如,在html标签中间),但有时看起来像是该块包含(或包装了)一个页面部分。 亚马逊还是一个很好的例子,它专注于页面上的重要内容(为什么用户在这里?他们想要什么?我们希望他们做什么?)并确保它首先被呈现。

The areas I've marked in this screenshot do not correspond to chunks exactly, but they show how the page renders progressively, using a combination of chunked response and source order:

我在此屏幕快照中标记的区域并不完全对应于大块,但它们结合分块响应和源顺序显示了页面如何逐步呈现:

  1. #1 - header. Every page has one. Get done with it.

    #1-标头。 每页都有一页。 完成它。
  2. #2 - buy now. This is what we want the user to do.

    #2-立即购买。 这就是我们希望用户要做的。
  3. #3 - image. The user wants to see what they're buying. Probably also helps Amazon minimize merchandise returns 🙂

    #3-图片用户想看看他们要买什么。 可能还有助于亚马逊最大程度地减少商品退货🙂
  4. #4 - title/price. Kind of important too.

    #4-标题/价格。 也很重要。

The rest of the page - reviews, comments, also buy... all this can wait, it's all secondary. Most of it is way below the fold anyway.

页面的其余部分-评论,评论,购买...所有这些都可以等待,这都是次要的。 无论如何,大多数都在折叠之下。

工具:无 (Tools: none)

Unfortunately, as far as I know, there's no tool that offers visibility into those chunks - what is the contents of each one and how does it looks like.

不幸的是,据我所知,没有工具可以提供对这些块的可见性-每个块的内容是什么以及它的外观如何。

Fiddler let's you see the encoded chunked response, but that doesn't help too much. At least it gives you an idea that the response was chunked - you can see under Inspectors/Transformer that there is a "Chunked Transfer-Encoding" checkbox.

Fiddler让我们看一下编码后的分块响应,但这并没有太大帮助。 至少它使您知道响应已分块-您可以在Inspectors / Transformer下看到“ Chunked Transfer-Encoding”复选框。

Also in Fiddler under the next tab - Headers, you can see the chunked encoding header. And also Fiddler helpfully tells you that the response has been encoded (the yellow message on top)

同样在Fiddler的下一个标签-Headers下,您可以看到分块的编码标头。 而且Fiddler也会有帮助地告诉您响应已被编码(顶部的黄色消息)

HTTPWatch let's you see the incomprehensible response, but it also tells you the number of chunks. Note that the number includes the last 0 in the response, so when it says 4 chunks it means actually 3.

HTTPWatch让您看到难以理解的响应,但是它也告诉您块的数量。 请注意,该数字包括响应中的最后0,因此当它说4个块时,实际上意味着3。

I also tried to fill the void in the tools department by attempting a Firefox extension. Unfortunately it didn't work, I couldn't find API exposed to extensions that would give me access to the raw encoded response. Looks like it would be possible as an extension to HTTPwatch or Fiddler though - both offer extensibility, both show the raw response.

我还尝试通过尝试Firefox扩展来填补工具部门的空白。 不幸的是,它没有用,我找不到暴露给扩展的API,这些扩展使我可以访问原始的编码响应。 看起来有可能作为HTTPwatch或Fiddler的扩展-两者都提供可扩展性,都显示原始响应。

For own consumption I did a PHP script to request the page and give me the chunks ungzipped. It's very primitive but you can give it a shot here. Test with Yahoo! Search for example.

为了自己使用,我做了一个PHP脚本来请求页面,并给我解压缩的块。 它非常原始,但是您可以在这里试一试。 用Yahoo!测试搜索例如

适用于gzip! (Works with gzip!)

A common concern is whether chunked encoding works together with gzipping the response. Yes, it does. In this presentation Steve Souders sheds some light (PPT, see slide #66) on how to address common issues and also gives flush() equivalents in languages other than PHP.

一个共同的问题是分块编码是否可以与gzipping响应一起使用。 是的,它确实。 在本演示中,Steve Souders就如何解决常见问题提供了一些启示(PPT,请参见幻灯片#66),并提供了PHP以外的其他语言的flush()等效项。

There's a number of things that can be in the way of successfully implementing chunked encoding+gzip including:

成功实现分块编码+ gzip的方式有很多,包括:

  • call ob_flush() in addition to flush() and careful if you have several output buffers started, you may need to iterate and flush all of them

    除了flush()之外,还请调用ob_flush() ,并注意是否已启动多个输出缓冲区,可能需要迭代并刷新所有它们

  • some browsers may require some minimal amount of content before starting to parse, IE needs at least 256 bytes

    有些浏览器在开始解析之前可能需要少量的内容,IE至少需要256个字节
  • you may need a newer version of Apache

    您可能需要较新版本的Apache
  • DeflateBufferSize in Apache may be set too high for your chunk size

    对于您的块大小,Apache中的DeflateBufferSize可能设置得太大

  • check the the user-contributed comments in the php.net manual for flush() for helpful advice and ideas

    检查php.net手册中用户提供的注释是否有flush()以获得有用的建议和想法

  • there's ob_implicit_flush() setting which may flush for you instead of you doing flush() every time

    ob_implicit_flush()设置可能会为您刷新,而不是每次都执行flush()

做吧! (Do it!)

It may be tricky to implement multiple (or even single) flushing, but it's well worth it. There's some server setup hurdles when it comes to gzip, but once you figure it out, you only do it once. As a reward you get faster loading times, plus progressive rendering so your page not only has faster time-to-onload by feels that way too.

实现多次(甚至是一次)冲洗可能很棘手,但这是值得的。 当涉及到gzip时,会有一些服务器设置障碍,但是一旦弄清楚了,就只做一次。 作为奖励,您可以获得更快的加载时间,以及渐进式渲染,因此您的页面不仅具有更快的加载时间,而且感觉也是如此。

Tell your friends about this post on Facebook and Twitter

FacebookTwitter上告诉您的朋友有关此帖子的信息

翻译自: https://www.phpied.com/progressive-rendering-via-multiple-flushes/

前端渐进式渲染

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值