diff options
author | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:40:17 -0500 |
---|---|---|
committer | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:40:17 -0500 |
commit | 33058f2b292b3a581333bdfb21b8f671898c5060 (patch) | |
tree | 51c3e392513ec574331b2d3f85c394445ea803c6 /files/zh-cn/web/performance | |
parent | 8b66d724f7caf0157093fb09cfec8fbd0c6ad50a (diff) | |
download | translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.gz translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.bz2 translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.zip |
initial commit
Diffstat (limited to 'files/zh-cn/web/performance')
8 files changed, 947 insertions, 0 deletions
diff --git a/files/zh-cn/web/performance/critical_rendering_path/index.html b/files/zh-cn/web/performance/critical_rendering_path/index.html new file mode 100644 index 0000000000..01a4663d76 --- /dev/null +++ b/files/zh-cn/web/performance/critical_rendering_path/index.html @@ -0,0 +1,66 @@ +--- +title: 关键渲染路径 +slug: Web/Performance/Critical_rendering_path +tags: + - CRP + - 关键渲染路径 + - 参考 + - 性能 + - 术语 +translation_of: Web/Performance/Critical_rendering_path +--- +<p>{{draft}}</p> + +<p><strong>关键渲染路径</strong>是浏览器将 HTML,CSS 和 JavaScript 转换为屏幕上的像素所经历的步骤序列。优化关键渲染路径可提高渲染性能。关键渲染路径包含了 <a href="/zh-CN/docs/Web/API/Document_Object_Model">文档对象模型 </a>(DOM),<a href="/zh-CN/docs/Web/API/CSS_Object_Model">CSS 对象模型 </a>(CSSOM),渲染树和布局。</p> + +<p>在解析 HTML 时会创建文档对象模型。HTML 可以请求 JavaScript,而 JavaScript 反过来,又可以更改 DOM。HTML 包含或请求样式,依次来构建 CSS 对象模型。浏览器引擎将两者结合起来以创建渲染树。布局确定页面上所有内容的大小和位置。确定布局后,将像素绘制到屏幕上。</p> + +<p>优化关键渲染路径可以缩短首次渲染的时间。了解和优化关键渲染路径对于确保重排和重绘可以每秒 60 帧的速度进行,以确保高效的用户交互并避免讨厌是很重要的。</p> + +<h2 id="理解_CRP">理解 CRP</h2> + +<p>Web 性能包含了服务器请求和响应、加载、执行脚本、渲染、布局和绘制每个像素到屏幕上。</p> + +<p>网页请求从 HTML 文件请求开始。服务器返回 HTML -- 响应头和数据。然后浏览器开始解析 HTML,转换收到的数据为 DOM 树。浏览器每次发现外部资源就初始化请求,无论是样式、脚本或者嵌入的图片引用。有时请求会阻塞,这意味着解析剩下的 HTML 会被终止直到重要的资源被处理。浏览器接着解析 HTML,发请求和构造 DOM 直到文件结尾 ,这时开始构造 CSS对象模型。等到 DOM 和 CSSOM 完成之后,浏览器构造渲染树,计算所有可见内容的样式。一旦渲染树完成布局开始,定义所有渲染树元素的位置和大小。完成之后,页面被渲染完成,或者说是绘制到屏幕上。</p> + +<h3 id="文本对象模型">文本对象模型</h3> + +<p>DOM构建是增量的。 HTML响应变成令牌(token),令牌变成节点,而节点又变成DOM树。 单个DOM节点以startTag令牌开始,以endTag令牌结束。 节点包含有关HTML元素的所有相关信息。 该信息是使用令牌描述的。 节点根据令牌层次结构连接到DOM树中。 如果另一组startTag和endTag令牌位于一组startTag和endTag之间,则您在节点内有一个节点,这就是我们定义DOM树层次结构的方式。</p> + +<p>节点数量越多,关键渲染路径中的后续事件将花费的时间就越长。 测一下吧! 几个额外的节点不会有什么区别,但“DIV癖”(divitis)可能会导致问题。</p> + +<h3 id="CSS_对象模型">CSS 对象模型</h3> + +<p>DOM 包含页面所有的内容。CSSOM 包含了页面所有的样式,也就是如何展示 DOM 的信息。CSSOM 跟 DOM 很像,但是不同。DOM 构造是增量的,CSSOM 却不是。CSS 是渲染阻塞的:浏览器会阻塞页面渲染直到它接收和执行了所有的 CSS。CSS 是渲染阻塞是因为规则可以被覆盖,所以内容不能被渲染直到 CSSOM 的完成。</p> + +<p>CSS 有其自身的规则集合用来定义标识。注意 CSS 中的 C 代表的是“层叠”。CSS 规则是级联的。随着解析器转换标识为节点,节点的后代继承了样式。像处理 HTML 那样的增量处理功能没有被应用到 CSS 上,因为后续规则可能被之前的所覆盖。CSS 对象模型随着 CSS 的解析而被构建,但是直到完成都不能被用来构建渲染树,因为样式将会被之后的解析所覆盖而不应该被渲染到屏幕上。</p> + +<p>从选择器性能的角度,更少的特定选择器是比更多的要快。例如,<code>.foo {}</code> 是比 <code>.bar .foo {}</code> 更快的因为当浏览器发现 <code>.foo</code> ,接下来必须沿着 DOM 向上走来检查 <code>.foo</code> 是不是有一个祖先 <code>.bar</code>。越是具体的标签浏览器就需要更多的工作,但这样的弊端未必值得优化。</p> + +<p>如果你测量过解析 CSS 的时间,你将会被浏览器实在地快所震惊。更具体的规则更昂贵因为它必须遍历更多的 DOM 树节点,但这所带来的额外的消耗通常很小。先测量一下。然后按需优化。特定化或许不是你的低垂的果实。在 CSS 中选择器的性能优化,提升仅仅是毫秒级的。有其他一些方式来<a href="/zh-CN/docs/Learn/Performance/CSS">优化 CSS</a>,例如压缩和使用媒体查询来异步处理 CSS 为非阻塞的请求。</p> + +<h3 id="渲染树">渲染树</h3> + +<p>渲染树包括了内容和样式:DOM 和 CSSOM 树结合为渲染树。为了构造渲染树,浏览器检查每个节点,从 DOM 树的根节点开始,并且决定哪些 CSS 规则被添加。</p> + +<p>渲染树只包含了可见内容。头部(通常)不包含任何可见信息,因此不会被包含在渲染树种。如果有元素上有 <code>display: none;</code>,它本身和其后代都不会出现在渲染树中。</p> + +<h3 id="布局">布局</h3> + +<p>一旦渲染树被构建,布局变成了可能。布局取决于屏幕的尺寸。布局这个步骤决定了在哪里和如何在页面上放置元素,决定了每个元素的宽和高,以及他们之间的相关性。</p> + +<p>什么是一个元素的宽?块级元素,根据定义,默认有父级宽度的 100%。一个宽度 50% 的元素,将占据父级宽度的一半。除非另外定义,body 有 100% 的宽,意味着它占据视窗的 100%。设备的宽度影响布局。 </p> + +<p>视窗的元标签定义了布局视窗的宽度,从而影响布局。没有的话,浏览器使用视窗的默认宽度,默认全屏浏览器通常是 960px。在默认情况下像你的手机浏览器的全屏浏览器,通过设置 <code><meta name="viewport" content="width=device-width"></code>,宽度将会是设备的宽度而不是默认的视窗宽度。设备宽度当用户在横向和纵向模式旋转他们的手机时将会改变。布局发生在每次设备旋转或浏览器缩放时。</p> + +<p>布局性能受 DOM 影响 -- 节点数越多,布局就需要更长的时间。布局将会变成瓶颈,如果期间需要滚动或者其他动画将会导致迟滞。20ms 的延迟在加载或者方向改变时或许还可以接受,但在动画或滚动时就会迟滞。任何渲染树改变的时候,像添加节点、改变内容或者在一个节点更新盒模型样式的时候布局就会发生。</p> + +<p>为了减小布局事件的频率和时长,批量更新或者避免改动盒模型属性。</p> + +<h3 id="绘制">绘制</h3> + +<p>最后已不是将像素绘制在屏幕上。一旦渲染树创建并且布局完成,像素就可以被绘制在屏幕上。加载时,整个屏幕被绘制出来。之后,只有受影响的屏幕区域会被重绘,浏览器被优化为只重绘需要绘制的最小区域。绘制时间取决于何种类型的更新被附加在渲染树上。绘制是一个非常快的过程,所以聚焦在提升性能时这大概不是最有效的部分,重点要记住的是当测量一个动画帧需要的时间需要考虑到布局和重绘时间。添加到节点的样式会增加渲染时间,但是移除样式增加的 0.001ms 或许不能让你的优化物有所值。记住先测量。然后你可决定它的优化优先级。</p> + +<h2 id="优化_CRP">优化 CRP</h2> + +<p>提升页面加载速度需要通过被加载资源的优先级、控制它们加载的顺序和减小这些资源的体积。性能提示包含 1)通过异步重要资源的下载来减小请求数量,2)优化必须的请求数量和每个请求的文件体积,3)通过区分关键资源的优先级来优化被加载关键资源的顺序,来缩短关键路径长度。</p> diff --git a/files/zh-cn/web/performance/css_javascript_animation_performance/index.html b/files/zh-cn/web/performance/css_javascript_animation_performance/index.html new file mode 100644 index 0000000000..8a4f98bb01 --- /dev/null +++ b/files/zh-cn/web/performance/css_javascript_animation_performance/index.html @@ -0,0 +1,76 @@ +--- +title: CSS and JavaScript animation performance +slug: Web/Performance/CSS_JavaScript_animation_performance +translation_of: Web/Performance/CSS_JavaScript_animation_performance +--- +<p class="summary">对众多应用程序而言,动画对提供友好的用户体验有着关键的作用,我们有很多方式生成 web 动画,比如 CSS {{cssxref("transition","transitions")}}/{{cssxref("animation","animations")}} 或者 JavaScript 动画 (使用 {{domxref("Window.requestAnimationFrame","requestAnimationFrame()")}}).</p> + +<p class="summary">在这篇文章中,我们分析 CSS 动画和 JavaScript 动画的性能差异</p> + +<h2 id="CSS_过渡和动画">CSS 过渡和动画</h2> + +<p>CSS 中过渡和动画都可以用于编写动画,它们都有各自的使用场景:</p> + +<ul> + <li>CSS {{cssxref("transition","transitions")}} 提供了一个简单的的方式去创造当前样式与结束状态样式之间的动画,比如一个 button 的普通状态和 hover 状态。尽管一个元素处于过渡状态中,新的过渡动画也会立即从当前样式开始,而不是直接跳转到CSS的最终状态。浏览 <a href="https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Using_CSS_transitions">Using CSS transitions</a> 以获取更多细节。</li> + <li>另一方面,CSS {{cssxref("animation","animations")}}, 允许开发者去通过一个初始状态属性值集合与最终状态属性值集合创造动画,而不是单单的初始和最终状态。 CSS animations 由两部分组成: 一个描述 CSS 动画的样式, 以及一个指定动画初始状态,中间状态以及最终状态样式的关键帧集合。浏览 <a href="https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Using_CSS_animations">Using CSS animations</a> 以获取更多细节.</li> +</ul> + +<p>就性能方面来说, 无论通过CSS animations 还是 transitions 创造动画,都没有区别。在这篇文章中二者都归类为基于CSS的动画.</p> + +<h2 id="requestAnimationFrame">requestAnimationFrame</h2> + +<p>{{domxref("Window.requestAnimationFrame","requestAnimationFrame()")}}提供了一种用JavaScript代码制作动画的高效方式。本方法的回调函数在绘制下一帧之前由浏览器调用。与需要一个延迟参数的{{domxref("WindowTimers.setTimeout","setTimeout()")}}/{{domxref("WindowTimers.setInterval","setInterval()")}}相比,requestAnimationFrame()效率高得多。开发人员可以在requestAnimationFrame回调函数中通过简单地改变元素的样式(或者更新画布绘制,等等)来创建动画。</p> + +<div class="note"> +<p><strong>注意</strong>:像CSS转换和动画一样,当页面在后台运行时,requestAnimationFrame()会暂停。</p> +</div> + +<p>更多细节请阅读 <a href="https://hacks.mozilla.org/2011/08/animating-with-javascript-from-setinterval-to-requestanimationframe/">animating with JavaScript from setinterval to requestAnimationFrame</a>.</p> + +<h2 id="性能对比_transitions_vs._requestAnimationFrame">性能对比:<br> + transitions vs. requestAnimationFrame</h2> + +<p>事实上,大多数场景下, 基于 CSS 的 动画几乎是跟 JavaScript 动画表现一致 — 至少在 FireFox 上是如此. 一些基于 Javascript 的动画库, 像 <a href="http://greensock.com/gsap">GSAP</a> and <a href="http://velocityjs.org/">Velocity.JS</a>, 甚至声称他们在性能上可以做得比 <a href="https://css-tricks.com/myth-busting-css-animations-vs-javascript/">native CSS transitions/animations</a> (原生的 CSS transitions/animations)更好. 这是可能的,因为在重绘事件发生之前,CSS transitions/animations 在主的 UI 线程仅仅是重新采集元素的样式, 这跟通过 <code>requestAnimationFrame()</code> 回调,获取重新采集元素样式是一样的, 也是在下一次重绘之前触发. 假如二者都是在主 UI 线程创建的动画,那它们在性能方面没有差异.</p> + +<p>在这一节,我们将会使用 FireFox 通过一个性能测试,去看看哪种动画方式更好</p> + +<h3 id="启用_FPS_工具">启用 FPS 工具</h3> + +<p>在进行示例之前,请启用FPS工具先查看当前帧速率:</p> + +<ol> + <li>在地址栏中,输入about:config;点击" I’ll be careful, I promise!"按钮,以输入配置屏幕。<br> + <img alt="" src="https://mdn.mozillademos.org/files/11137/Pic1.png" style="height: 349px; width: 600px;"></li> + <li>在搜索栏中搜索layers.acceleration.draw-fps首选项</li> + <li>双击该条目将值设置为true。.现在您可以在Firefox窗口的左上角看到三个紫色的框。第一个框代表FPS。<br> + <img alt="" src="https://mdn.mozillademos.org/files/11139/Pic2.png" style="height: 215px; width: 562px;"></li> +</ol> + +<h3 id="运行性能测试">运行性能测试</h3> + +<p>开始在下面的测试中,总共1000个{{htmlelement("div")}}元素通过css动画进行坐标转换。</p> + +<p><span style="line-height: 16.7999992370605px;">{{JSFiddleEmbed("https://jsfiddle.net/zt94oew2/1/","","480")}}</span></p> + +<p>动画可以通过点击"toggle"按钮切换到 <code>requestAnimationFrame()</code> 。</p> + +<p>试着两个都运行一下,比较两者的FPS值(第一个紫色框),可以看到CSS动画和<code>requestAnimationFrame()是非常接近的</code>。</p> + +<h3 id="脱离主线程的动画">脱离主线程的动画</h3> + +<p>即使是上面给出的测试结果,我们仍然认为CSS动画是更好的选择。为什么?关键是只要动画涉及的属性不引起reflow(重新布局)(参考<a href="http://csstriggers.com/">CSS triggers</a>获得更多信息),我们可以把采用操作移出主线程。最常见的属性是CSS transform。如果一个元素被提升为一个<a href="https://wiki.mozilla.org/Gecko:Overview#Graphics">layer</a>,transform属性动画就可以在GPU中进行。这意味着更好地性能,特别实在移动设备上。在<a href="https://wiki.mozilla.org/Platform/GFX/OffMainThreadCompositing">OffMainThreadCompositing</a>上寻找更多细节。</p> + +<p>要在火狐中激活OMTA (脱离主线程的动画) ,你需要前往<em>about:config然后搜索</em> <code>layers.offmainthreadcomposition.async-animations</code> 。切换到 <code>true</code>.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/11141/Pic3.png" style="height: 210px; width: 536px;"></p> + +<p>激活之后,再次运行上面的例子。可以看到CSS动画的帧速率现在高多了。</p> + +<div class="note"> +<p><strong>注意</strong>: 在Nightly/Developer 版本,你可能看到OMTA缺省就是激活的,所以你需要反过来测试。(先测试激活OMTA的情况,然后是没有激活的情况)</p> +</div> + +<h2 id="总结">总结</h2> + +<p>浏览器可以优化渲染流程。总之,我们总是可以尽可能通过CSS过渡/动画创建动画。如果你的动画真的很复杂,你可能不得不依赖于JavaScript动画。</p> diff --git a/files/zh-cn/web/performance/dns-prefetch/index.html b/files/zh-cn/web/performance/dns-prefetch/index.html new file mode 100644 index 0000000000..56f6946b97 --- /dev/null +++ b/files/zh-cn/web/performance/dns-prefetch/index.html @@ -0,0 +1,68 @@ +--- +title: dns-prefetch +slug: Web/Performance/dns-prefetch +tags: + - Web Performance + - dns-prefetch +translation_of: Web/Performance/dns-prefetch +--- +<p><code><strong>DNS-prefetch</strong></code> (<strong>DNS 预获取</strong>) 是尝试在请求资源之前解析域名。这可能是后面要加载的文件,也可能是用户尝试打开的链接目标。</p> + +<h2 id="为什么要使用_dns-prefetch">为什么要使用 dns-prefetch?</h2> + +<p>当浏览器从(第三方)服务器请求资源时,必须先将该<a href="https://wiki.developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS">跨域</a>域名解析为 IP地址,然后浏览器才能发出请求。此过程称为 DNS解析。DNS 缓存可以帮助减少此延迟,而 DNS解析可以导致请求增加明显的延迟。对于打开了与许多第三方的连接的网站,此延迟可能会大大降低加载性能。</p> + +<p><code>dns-prefetch</code> 可帮助开发人员掩盖 DNS解析延迟。 <a href="https://wiki.developer.mozilla.org/en-US/docs/Web/HTML/Element/link">HTML <code><link></code>元素</a> 通过 dns-prefetch的 <a href="https://wiki.developer.mozilla.org/zh-CN/docs/Web/HTML/Attributes/rel">rel 属性</a>值提供此功能。然后在<a href="https://wiki.developer.mozilla.org/zh-CN/docs/Web/HTML/Attributes"> href属性</a>中指要<a href="https://wiki.developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS">跨域</a>的域名:</p> + +<h2 id="句法">句法</h2> + +<pre class="brush: html notranslate"><link rel="dns-prefetch" href="https://fonts.googleapis.com/"> </pre> + +<h2 id="例子">例子</h2> + +<pre class="notranslate"><html> + <head> + <link rel="dns-prefetch" href="https://fonts.gstatic.com/"> + <!-- and all other head elements --> + </head> + <body> + <!-- your page content --> + </body> +</html></pre> + +<p>每当站点引用跨域域上的资源时,都应在 <a href="https://wiki.developer.mozilla.org/zh-CN/docs/Web/HTML/Element/head"><head> 元素</a>中放置 dns-prefetch提示,但是要记住一些注意事项。</p> + +<h2 id="最佳实践">最佳实践</h2> + +<p id="Three_things_to_keep_in_mind">请记住以下三点:</p> + +<p>首先,<code>dns-prefetch</code> 仅对<a href="https://wiki.developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS">跨域</a>域上的 DNS查找有效,因此请避免使用它来指向您的站点或域。这是因为,到浏览器看到提示时,您站点域背后的IP已经被解析。</p> + +<p>其次,还可以通过使用 <a href="https://wiki.developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Link">HTTP链接字段</a>将 <code>dns-prefetch</code>(以及其他资源提示)指定为 H<a href="https://wiki.developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers">TTP标头</a>:</p> + +<pre class="notranslate">Link: <https://fonts.gstatic.com/>; rel=dns-prefetch</pre> + +<p>第三,考虑将 <code>dns-prefetch</code> 与 <code>preconnect(</code>预连接<code>)</code>提示配对。尽管 <code>dns-prefetch</code> 仅执行 DNS查找,但<code>preconnect</code> 会建立与服务器的连接。如果站点是通过HTTPS服务的,则此过程包括DNS解析,建立TCP连接以及执行TLS握手。将两者结合起来可提供进一步减少<a href="https://wiki.developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS">跨域请求</a>的感知延迟的机会。您可以安全地将它们一起使用,如下所示:</p> + +<pre class="brush: html notranslate"><link rel="preconnect" href="https://fonts.gstatic.com/" crossorigin> +<link rel="dns-prefetch" href="https://fonts.gstatic.com/"> +</pre> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: 如果页面需要建立与许多第三方域的连接,则将它们预先连接会适得其反。 <code>preconnect</code> 提示最好仅用于最关键的连接。对于其他的,只需使用 <code><link rel="dns-prefetch"></code> 即可节省第一步的时间-DNS查找。</p> +</div> + +<p>配对这些提示的逻辑是因为对dns-prefetch的支持比对预连接的支持要好。不支持预连接的浏览器仍然可以通过回退到dns-prefetch来获得更多好处。由于这是HTML功能,因此非常容错。如果不支持的浏览器遇到dns-prefetch提示(或任何其他资源提示),则您的网站不会中断。您只是不会获得它提供的好处。</p> + +<p>一些资源(如字体)以匿名模式加载。在这种情况下,应使用预连接提示设置 <a href="https://wiki.developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS">crossorigin</a> 属性。如果您省略它,则浏览器将仅执行DNS查找。</p> + +<h2 id="查看更多">查看更多</h2> + +<ul> + <li><a href="https://wiki.developer.mozilla.org/en-US/docs/Web/HTML/Element/link"><link></a></li> + <li><a href="https://wiki.developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel">HTML attribute: rel</a></li> + <li><a href="https://wiki.developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes">crossorigin</a></li> + <li><a href="https://wiki.developer.mozilla.org/en-US/docs/Web/HTTP/CORS">Cross-Origin Resource Sharing (CORS)</a></li> + <li><a href="https://wiki.developer.mozilla.org/en-US/docs/Web/HTTP/Headers">HTTP headers</a></li> + <li><a href="https://wiki.developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Link">HTTP header </a><a href="https://wiki.developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Link" title="The HTTP Link entity-header field provides a means for serialising one or more links in HTTP headers. It is semantically equivalent to the HTML <link> element.">Link</a></li> +</ul> diff --git a/files/zh-cn/web/performance/index.html b/files/zh-cn/web/performance/index.html new file mode 100644 index 0000000000..ea03afafe8 --- /dev/null +++ b/files/zh-cn/web/performance/index.html @@ -0,0 +1,276 @@ +--- +title: Web 性能 +slug: Web/Performance +tags: + - API + - HTML + - JavaScript + - Web + - 性能 + - 性能优化 +translation_of: Web/Performance +--- +<p>Web 性能是客观的衡量标准,是用户对加载时间和运行时的直观体验。Web 性能指页面加载到可交互和可响应所消耗的时间,以及页面在交互时的流畅度——滚动是否顺滑?按钮能否点击?弹窗能否快速打开,动画是否平滑?Web 性能既包括客观的度量如加载时间,每秒帧数和到页面可交互的时间;也包括用户的对页面内容加载时间的主观感觉。 </p> + +<p>页面响应时间越长,越多的用户就会放弃该网站。重要的是,通过使体验尽可能早地变得可用和交互,同时异步地加载长尾体验部分,来最大程度地减少加载和响应时间,并添加其他功能以降低延迟。</p> + +<p>有很多工具,API 和最佳实践帮助我们测量和改进网页性能。本章对此有所讲解。</p> + +<h2 id="关键性能指南">关键性能指南</h2> + +<p>{{LandingPageListSubpages}}</p> + +<div class="cleared topicpage-table"> +<div class="section"> +<h2 id="初学者教程">初学者教程</h2> + +<p>MDN <a href="/zh-CN/docs/Learn/Performance">Web 性能学习专区</a> 有着涵盖性能要素的最新教程。 如果您是性能新手,请从这里开始:</p> + +<dl> + <dt><a href="/zh-CN/docs/Learn/Performance/web_performance_overview">Web 性能:概述</a></dt> + <dd>Web性能学习路径概述。 在这里开始您的旅程。</dd> + <dt><a href="/zh-CN/docs/Learn/Performance/What_is_web_performance">什么是 Web 性能?</a></dt> + <dd>该文从一个模块开始,很好地讲述了性能到底是什么——包括我们在考虑性能时需要考虑的工具、指标、API、网络和人群,以及如何使性能成为 Web 开发工作流程的一部分。</dd> + <dt><a href="/zh-CN/docs/Learn/Performance/perceived_performance">用户如何看待性能?</a></dt> + <dd>比网站在毫秒内响应速度更重要的是,用户对网站的感知速度有多快。这些感知受到页面实际加载时间、空闲、用户交互响应以及滚动和其他动画的平滑度的影响。在本文中,我们将随着最佳练习来提升用户感知(而不是实际时间)并讨论各种加载指标、动画和响应性指标。</dd> + <dt><a href="/zh-CN/docs/Learn/Performance/web_performance_basics">Web 性能基础</a></dt> + <dd>除了HTML,CSS,JavaScript和媒体文件这些前端模块之外,还有其他影响Web性能的因素,它们可能会导致应用程序变慢,或在主观和客观上使应用程序变快。有许多与Web性能相关的API、开发人员工具、最佳实践和不当做法。我们将在基础层面上介绍这些影响因素,并提供进阶优化其中每一项性能的链接。</dd> + <dt><a href="/zh-CN/docs/Learn/Performance/HTML">HTML 性能特性</a></dt> + <dd>标签的某些属性和顺序可能会影响网站性能。 通过最大程度地减少DOM节点的数量,确保使用最佳顺序和属性,包括样式、脚本、媒体和第三方脚本等内容,可以大大改善用户体验。 该文详细介绍了如何使用 HTML 来确保最佳性能。</dd> + <dt><a href="/zh-CN/docs/Learn/Performance/Multimedia">多媒体:图像与视频</a></dt> + <dd>Web 性能的最小代价通常是媒体优化。基于每个用户代理的能力、大小和像素密度来服务不同的媒体文件已成为可能。另外,如从背景图像中删除音频轨迹,可进一步提升性能。该文讨论视频、音频和图像内容对性能的影响,以及确保影响尽可能小的方法。</dd> + <dt><a href="/zh-CN/docs/Learn/Performance/CSS_performance">CSS 性能特性</a></dt> + <dd>CSS 对于提高性能来说可能是一个不太重要的优化点,但是某些 CSS 特性对性能的影响比其他特性更大。在该文中,我们将研究一些影响性能的 CSS 属性,并提供样式处理的建议方法,以确保性能不受负面影响。</dd> + <dt><a href="/zh-CN/docs/Learn/Performance/JavaScript">JavaScript 性能最佳实践</a></dt> + <dd>如果正确使用JavaScript,则可以提供交互式和身临其境的 Web 体验——否则可能会严重损害下载时间、渲染时间、应用内性能、电池寿命和用户体验。 该文概述了一些值得思考的 JavaScript 最佳实践,以确保即使复杂的内容也尽可能地具有高性能。</dd> + <dt><a href="/zh-CN/docs/Learn/Performance/Mobile">移动端性能</a></dt> + <dd>随着移动设备上的Web访问普及,并且所有移动平台都具有功能完善的Web浏览器,但由于受限于带宽、CPU、电池续航等因素,因此考虑这些平台上Web内容的性能非常重要。 本文着眼于特定于移动设备的性能注意事项。</dd> +</dl> +</div> + +<div class="section"> +<h2 class="Using_Performance_APIs" id="Using_Performance_APIs" name="Using_Performance_APIs">使用 Performance API</h2> + +<dl> + <dt><a href="/zh-CN/docs/Web/API/Performance_API/Using_the_Performance_API">Performance API</a></dt> + <dd>该指南介绍了如何使用 <a class="external external-icon" href="https://w3c.github.io/hr-time/" rel="noopener">High-Resolution Time</a> 标准中定义的 <code><a href="/zh-CN/docs/Web/API/Performance" title="The Performance interface provides access to performance-related information for the current page. It's part of the High Resolution Time API, but is enhanced by the Performance Timeline API, the Navigation Timing API, the User Timing API, and the Resource Timing API.">Performance</a></code> 接口。</dd> + <dt><a href="/zh-CN/docs/Web/API/Resource_Timing_API/Using_the_Resource_Timing_API">Resource Timing API</a></dt> + <dd><a href="/zh-CN/docs/Web/API/Resource_Timing_API">资源加载和定时加载</a> 这些资源,包括管理资源缓冲区和处理CORS</dd> + <dt><a href="/zh-CN/docs/Web/API/Performance_Timeline/Using_Performance_Timeline">性能时间线</a></dt> + <dd><a href="/zh-CN/docs/Web/API/Performance_Timeline">Performance Timeline</a> 标准定义了对 <a href="/zh-CN/docs/Web/API/Performance" title="The Performance interface provides access to performance-related information for the current page. It's part of the High Resolution Time API, but is enhanced by the Performance Timeline API, the Navigation Timing API, the User Timing API, and the Resource Timing API."><code>Performance</code></a> 接口的扩展,以支持应用程序中的客户端延迟测量。这些接口一起可以用来帮助识别应用程序的性能瓶颈。</dd> + <dt><a href="/zh-CN/docs/Web/API/User_Timing_API/Using_the_User_Timing_API">User Timing API</a> </dt> + <dd>使用创建特定于应用程序的时间戳 <a href="/zh-CN/docs/Web/API/User_Timing_API">user timing API</a>'s “标记”和“度量”条目类型-它们是浏览器性能时间轴的一部分。</dd> + <dt><a href="/zh-CN/docs/Web/API/Frame_Timing_API/Using_the_Frame_Timing_API">Frame Timing API</a></dt> + <dd><code><a href="/zh-CN/docs/Web/API/PerformanceFrameTiming">PerformanceFrameTiming</a></code> 接口提供有关浏览器事件循环的<em>帧</em>计时数据。</dd> + <dt><a href="/zh-CN/docs/Web/API/Beacon_API/Using_the_Beacon_API">Beacon API</a></dt> + <dd><small>使用 <a href="/zh-CN/docs/Web/API/Beacon_API">Beacon</a> 接口调度发送给服务器的异步非阻塞请求。</small></dd> + <dt><a href="/zh-CN/docs/Web/API/Intersection_Observer_API/Timing_element_visibility">Intersection Observer API</a></dt> + <dd>通过 <a href="/zh-CN/docs/Web/API/Intersection_Observer_API">Intersection Observer API</a> 学习对元素可见性的监测,并在关注的元素变得可见时被异步通知。</dd> +</dl> + +<h2 class="Other_documentation" id="Other_documentation" name="Other_documentation">其他文档</h2> + +<dl> + <dt><a href="/zh-CN/docs/Tools/Performance">开发者工具中与性能相关的功能</a></dt> + <dd>本节提供有关如何使用和理解开发人员工具中的性能特性的信息,包括 <a href="/zh-CN/docs/Tools/Performance/Waterfall">Waterfall</a>, <a href="/zh-CN/docs/Tools/Performance/Call_Tree">Call Tree</a>, 和 <a href="/zh-CN/docs/Tools/Performance/Flame_Chart">Flame Charts</a>.</dd> + <dt></dt> + <dt><a href="/zh-CN/docs/Performance/Profiling_with_the_Built-in_Profiler">使用内置分析器进行分析</a></dt> + <dd>了解如何使用Firefox的内置分析器来分析应用程序性能。</dd> +</dl> +</div> +</div> + +<h2 id="各种术语">各种术语</h2> + +<div class="index"> +<ul class="index"> + <li>{{glossary('Beacon')}}</li> + <li>{{glossary('Brotli compression')}}</li> + <li>{{glossary('Client hints')}}</li> + <li>{{glossary('Code splitting')}}</li> + <li>{{glossary('CSSOM')}}</li> + <li>{{glossary('Domain sharding')}}</li> + <li>{{glossary('Effective connection type')}}</li> + <li>{{glossary('First contentful paint')}}</li> + <li>{{glossary('First CPU idle')}}</li> + <li>{{glossary('First input delay')}}</li> + <li>{{glossary('First interactive')}}</li> + <li>{{glossary('First meaningful paint')}}</li> + <li>{{glossary('First paint')}}</li> + <li>{{glossary('HTTP')}}</li> + <li>{{glossary('HTTP_2', 'HTTP/2')}}</li> + <li>{{glossary('Jank')}}</li> + <li>{{glossary('Latency')}}</li> + <li>{{glossary('Lazy load')}}</li> + <li>{{glossary('Long task')}}</li> + <li>{{glossary('Lossless compression')}}</li> + <li>{{glossary('Lossy compression')}}</li> + <li>{{glossary('Main thread')}}</li> + <li>{{glossary('Minification')}}</li> + <li>{{glossary('Network throttling')}}</li> + <li>{{glossary('Packet')}}</li> + <li>{{glossary('Page load time')}}</li> + <li>{{glossary('Page prediction')}}</li> + <li>{{glossary('Parse')}}</li> + <li>{{glossary('Perceived performance')}}</li> + <li>{{glossary('Prefetch')}}</li> + <li>{{glossary('Prerender')}}</li> + <li>{{glossary('QUIC')}}</li> + <li>{{glossary('RAIL')}}</li> + <li>{{glossary('Real User Monitoring')}}</li> + <li>{{glossary('Resource Timing')}}</li> + <li>{{glossary('Round Trip Time (RTT)')}}</li> + <li>{{glossary('Server Timing')}}</li> + <li>{{glossary('Speculative parsing')}}</li> + <li>{{glossary('Speed index')}}</li> + <li>{{glossary('SSL')}}</li> + <li>{{glossary('Synthetic monitoring')}}</li> + <li>{{glossary('TCP handshake')}}</li> + <li>{{glossary('TCP slow start')}}</li> + <li>{{glossary('Time to first byte')}}</li> + <li>{{glossary('Time to interactive')}}</li> + <li>{{glossary('TLS')}}</li> + <li>{{glossary('TCP', 'Transmission Control Protocol (TCP)')}}</li> + <li>{{glossary('Tree shaking')}}</li> + <li>{{glossary('Web performance', 'Web 性能')}}</li> +</ul> +</div> + +<h2 id="即将编写的文档">即将编写的文档</h2> + +<dl> + <dt><a href="/zh-CN/docs/Learn/Performance/JavaScript">JavaScript 性能最佳实践</a></dt> + <dd>JavaScript,如果使用得当,可以提供交互式和身临其境的web体验...或者它会严重影响下载时间、渲染时间、应用内性能、电池寿命和用户体验。本文概述了一些JavaScript最佳实践,这些实践可以确保即使是复杂内容的性能也是最高的。</dd> + <dt><a href="/zh-CN/docs/Learn/Performance/Mobile">移动端性能</a></dt> + <dd>由于移动设备上的web访问非常流行,而且所有移动平台都有成熟的web浏览器,但带宽、CPU和电池寿命可能有限,因此考虑这些平台上web内容的性能非常重要。本文还讨论了移动设备特定的性能考虑因素。</dd> + <dt>Web 字体性能</dt> + <dd>性能方面一个经常被忽视的方面是web字体。Web字体在Web设计中比以往任何时候都更加突出,然而许多开发人员只是简单地将它们从第三方服务中嵌入而不考虑它。在本文中,我们将介绍如何使用高效的文件格式和子设置使字体文件尽可能小。从那以后,我们将继续讨论浏览器如何文本,以及如何使用 CSS 和 JavaScript 功能,以确保您的字体快速呈现,并将对用户体验的干扰降到最低。</dd> + <dt>性能瓶颈</dt> + <dd></dd> + <dt>理解带宽</dt> + <dd> + <div> + <div class="public-DraftStyleDefault-block public-DraftStyleDefault-ltr"><span><span>带宽是以兆位(Mb)或千位(Kb)为单位的每秒可发送的数据量。本文将解释带宽在富媒体internet应用程序中的作用,如何测量带宽,以及如何优化应用程序以最大限度地利用可用带宽。</span></span></div> + </div> + </dd> + <dt>TLS 在性能中的作用</dt> + <dd> + <p>TLS或HTTPS(我们通常称之为TLS)对于创建安全和安全的用户体验至关重要。虽然硬件降低了TLS对服务器性能的负面影响,但它仍然代表了我们等待浏览器连接到服务器所花费的大量时间。本文解释了TLS握手过程,并提供了一些减少时间的技巧,例如OCSP装订、HSTS预加载头,以及资源提示在为第三方屏蔽TLS延迟方面的潜在作用。</p> + </dd> + <dt>阅读性能图表</dt> + <dd>开发人员工具提供有关性能、内存和网络请求的信息。知道如何阅读 <a href="/zh-CN/docs/Tools/Performance/Waterfall">waterfall</a> charts, <a href="/zh-CN/docs/Tools/Performance/Call_Tree">call trees</a>, traces, <a href="/zh-CN/docs/Tools/Performance/Flame_Chart">flame charts</a> ,和 <a href="/zh-CN/docs/Tools/Performance/Allocations">allocations</a> 在浏览器中,开发人员工具将帮助您理解其他性能工具中的瀑布图和火焰图。</dd> + <dt>其他媒体格式</dt> + <dd>当涉及到图像和视频时,有比你可能意识到的更多的格式。其中一些格式可以通过进一步减小文件大小来进一步优化富媒体页面。在本指南中,我们将讨论一些替代的媒体格式,如何负责任地使用它们,使不受支持的浏览器不被冷落,以及一些关于将现有资源转换为它们的高级指导。</dd> + <dt>分析 JavaScript bundle</dt> + <dd>毫无疑问,JavaScript是现代web开发的重要组成部分。虽然您应该一直努力减少在应用程序中使用的JavaScript数量,但是很难知道从哪里开始。在本指南中,我们将向您展示如何分析应用程序的脚本捆绑包,以便您知道您在使用什么,以及如何检测应用程序在捆绑包之间是否包含重复的脚本。</dd> + <dt><a href="/zh-CN/docs/Web/Performance/Lazy_loading">延迟加载</a></dt> + <dd>在初始页面加载时并不总是需要加载所有web应用程序资产。延迟加载是将页面上的资产(如脚本、图像等)的加载推迟到稍后的时间点,即实际需要这些资产的时候。</dd> + <dt>使用动态 import 延迟加载 JavaScript</dt> + <dd>当开发人员听到术语“延迟加载”时,他们会立即想到当滚动到视口时加载的折叠图像下方。但是你知道你也可以延迟加载JavaScript吗?在本指南中,我们将讨论dynamic import()语句,这是现代浏览器中按需加载JavaScript模块的功能。当然,由于这个特性不是到处都可用的,我们还将向您展示如何配置您的工具以广泛兼容的方式使用此特性。</dd> + <dt><a href="/zh-CN/docs/Web/Performance/Controlling_resource_delivery_with_resource_hints">使用资源提示(resource hints)控制资源传输</a></dt> + <dd>浏览器通常比我们更了解资源的优先级和交付,但是他们离克莱里奥万特还很远。本机浏览器特性使我们能够在浏览器应该连接到另一个服务器时提示浏览器,或者在浏览器知道它需要资源之前预先加载资源。如果使用得当,这可以使快速体验看起来更快。在本文中,我们将介绍诸如rel=preconnect、rel=dns prefetch、rel=prefetch和rel=preload等本机浏览器功能,以及如何使用它们来发挥您的优势。</dd> + <dt><a href="/zh-CN/docs/Web/Performance/Performance_budgets">性能预算</a></dt> + <dd>营销、设计和销售需求,以及开发人员的经验,通常是广告膨胀、第三方脚本和其他会降低web性能的功能。为了帮助设置优先级,设置一个性能预算是很有帮助的:一组在开发阶段不能超过的限制。在本文中,我们将讨论创建和坚持绩效预算。</dd> + <dt><a href="/zh-CN/docs/Web/Performance/Checklist">Web 性能检查清单</a></dt> + <dd>一个在开发应用程序时要考虑性能清单,其中包含如何实现每个特性的教程链接,包括 Service Worker、性能问题诊断、字体加载最佳实践、客户端提示、创建高效的动画等。</dd> + <dt><a href="/zh-CN/docs/Web/Performance/Mobile_performance_checklist">Mobile </a><a href="/zh-CN/docs/Web/Performance/Checklist">性能检查清单</a></dt> + <dd>A concise checklist of performance considerations impacting mobile network users on hand-held, battery operated devices.</dd> +</dl> + +<h2 id="也可以看看">也可以看看</h2> + +<p>HTML</p> + +<ul> + <li><a href="/zh-CN/docs/Web/HTML/Element/picture"><code><picture></code> 元素</a></li> + <li><a href="/zh-CN/docs/Web/HTML/Element/video"><code><video></code> 元素</a></li> + <li><a href="/zh-CN/docs/Web/HTML/Element/source">The <code><source></code> Element</a></li> + <li><a href="/zh-CN/docs/Web/HTML/Element/img#Attributes">The <code><img> srcset</code> attribute</a> + <ul> + <li>响应式图片</li> + </ul> + </li> + <li><a href="/zh-CN/docs/Web/HTML/Preloading_content">使用 <code>rel="preload"</code> 预加载内容 —— </a><a href="https://w3c.github.io/preload/">(https://w3c.github.io/preload/ </a>)</li> +</ul> + +<p>CSS</p> + +<ul> + <li><a href="/zh-CN/docs/Web/CSS/will-change">will-change</a></li> + <li>GPU v CPU</li> + <li>测量布局</li> + <li>字体加载最佳实践</li> +</ul> + +<p>JavaScript</p> + +<ul> + <li><a href="/zh-CN/docs/Web/Events/DOMContentLoaded">DOMContentLoaded</a></li> + <li><a href="/zh-CN/docs/Glossary/Garbage_collection">垃圾回收机制(GC)</a></li> + <li><a href="/zh-CN/docs/Web/API/window/requestAnimationFrame">requestAnimationFrame</a></li> +</ul> + +<p>APIs</p> + +<ul> + <li><a href="/zh-CN/docs/Web/API/Performance_API">Performance API</a></li> + <li><a href="/zh-CN/docs/Web/API/Navigation_timing_API">Navigation Timing API</a></li> + <li><a href="/zh-CN/docs/Web/API/Media_Capabilities_API/Using_the_Media_Capabilities_API">Media Capabilities API</a></li> + <li><a href="/zh-CN/docs/Web/API/Network_Information_API">Network Information API</a></li> + <li><a href="/zh-CN/docs/Web/API/PerformanceNavigationTiming">PerformanceNavigationTiming</a></li> + <li><a href="/zh-CN/docs/Web/API/Battery_Status_API">Battery Status API</a></li> + <li><a href="/zh-CN/docs/Web/API/Navigator/deviceMemory">Navigator.deviceMemory</a></li> + <li><a href="/zh-CN/docs/Web/API/Intersection_Observer_API">Intersection Observer</a></li> + <li><a href="/zh-CN/docs/Web/API/User_Timing_API/Using_the_User_Timing_API">Using the User Timing AP</a>I</li> + <li><a href="/zh-CN/docs/Web/API/Long_Tasks_API">Long Tasks API</a></li> + <li><a href="/zh-CN/docs/Web/API/DOMHighResTimeStamp">High Resolution Timing API</a> (<a href="https://w3c.github.io/hr-time/">https://w3c.github.io/hr-time/)</a></li> + <li><a href="/zh-CN/docs/Web/API/Resource_Timing_API/Using_the_Resource_Timing_API">Resource Timing API</a></li> + <li><a href="/zh-CN/docs/Web/API/Page_Visibility_API">页面可见性</a></li> + <li><a href="/zh-CN/docs/Web/API/Background_Tasks_API">Cooperative Scheduling of Background Tasks API</a> + <ul> + <li style="margin-top: 0.25em;"><a href="/zh-CN/docs/Web/API/Window/requestIdleCallback">requestIdleCallback() </a></li> + </ul> + </li> + <li><a href="/zh-CN/docs/Web/API/Beacon_API/Using_the_Beacon_API">Beacon API</a></li> + <li>资源提示 - <a href="/zh-CN/docs/Web/HTTP/Headers/X-DNS-Prefetch-Control">dns-prefetch</a>, preconnect, <a href="/zh-CN/docs/Web/HTTP/Link_prefetching_FAQ">prefetch</a>, and prerender</li> + <li><a href="/zh-CN/docs/Web/API/FetchEvent/navigationPreload">Fetchevent.navigationPreload</a></li> + <li><a href="/zh-CN/docs/Web/API/PerformanceServerTiming">Performance Server Timing API</a></li> +</ul> + +<p>Headers</p> + +<ul> + <li><a href="/zh-CN/docs/Web/HTTP/Headers/Content-Encoding">Content-encoding</a></li> + <li>HTTP/2</li> + <li><a href="/zh-CN/docs/Glossary/GZip_compression">gZip</a></li> + <li>Client Hints</li> +</ul> + +<p>工具</p> + +<ul> + <li><a href="/zh-CN/docs/Tools/Performance">Firefox 开发者工具中的性能面板</a></li> + <li>火焰图</li> + <li>网络面板</li> + <li>瀑布图</li> +</ul> + +<p>其他指标</p> + +<ul> + <li>速度指数(Speed Index)和感知速度指数(Perceptual Speed Index)</li> +</ul> + +<p>最佳实践</p> + +<ul> + <li><a href="/zh-CN/docs/Web/API/Service_Worker_API/Using_Service_Workers">使用 Service Workers</a></li> + <li><a href="/zh-CN/docs/Web/API/Web_Workers_API/Using_web_workers">使用 Web Workers</a> + <ul> + <li><a href="/zh-CN/docs/Web/API/Web_Workers_API">Web Workers API</a></li> + </ul> + </li> + <li><a href="/zh-CN/docs/Web/Apps/Progressive/Offline_Service_workers">PWA</a></li> + <li><a href="/zh-CN/docs/Web/HTTP/Caching">缓存</a></li> + <li>内容分发网络 (CDN)</li> +</ul> diff --git a/files/zh-cn/web/performance/lazy_loading/index.html b/files/zh-cn/web/performance/lazy_loading/index.html new file mode 100644 index 0000000000..6399c43e0f --- /dev/null +++ b/files/zh-cn/web/performance/lazy_loading/index.html @@ -0,0 +1,122 @@ +--- +title: Lazy loading +slug: Web/Performance/Lazy_loading +tags: + - Lazy-loading + - Web Performance + - 延迟加载 + - 性能优化 + - 懒加载 +translation_of: Web/Performance/Lazy_loading +--- +<p><span class="seoSummary"><strong>延迟加载(懒加载) </strong></span>是一种将资源标识为非阻塞(非关键)资源并仅在需要时加载它们的策略。<span class="seoSummary"><span> </span></span>这是一种缩短<a href="https://wiki.developer.mozilla.org/zh-CN/docs/Web/Performance/Critical_rendering_path">关键渲染路径</a>长度的方法,可以缩短页面加载时间。</p> + +<p>延迟加载可以在应用程序的不同时刻发生,但通常会在某些用户交互(例如滚动和导航)上发生。</p> + +<h2 id="概览">概览</h2> + +<p>随着网络的发展,我们已经看到发送给用户的资产数量和规模都在急剧增加。从2011年到2019年,台式机的资源中位数从 <strong>~100KB </strong>增至 <strong>~400KB</strong>,移动版的资源中位数从 <strong>~50KB</strong> 增至<strong>~350KB</strong>。图像大小已从台式机上的<strong>~250KB </strong>增至 <strong>~900KB</strong>,而移动设备上的 <strong>~100KB</strong>增至<strong>~850KB</strong>。</p> + +<p>One of the methods we can use to tackle this problem is to shorten the <a href="/en-US/docs/Web/Performance/Critical_rendering_path">Critical Rendering Path</a> length by lazy loading resources that are not critical for the first render to happen.<br> + A practical example would be when, you land on the home page of an e-commerce site which has a link to a cart page/section and all its resources (JS, CSS, images...) are downloaded <strong>only</strong> when the user navigates to that cart page.</p> + +<h2 id="策略">策略</h2> + +<p>延迟加载可以通过多种策略应用于多个资源。</p> + +<h3 id="一般"> 一般</h3> + +<p id="Code_splitting">代码拆分<br> + JavaScript, CSS and HTML can be split into smaller chunks. This enables sending the minimal code required to provide value upfront, improving page-load times. The rest can be loaded on demand.</p> + +<ul> + <li> Entry point splitting: separates code by entry point(s) in the app</li> + <li> Dynamic splitting: separates code where <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import">dynamic import()</a> statements are used</li> +</ul> + +<h3 id="JavaScript"> JavaScript</h3> + +<p>脚本类型模块<br> + 任何类型为 <code>type="module" </code>的脚本标签都被视为一个 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Modules">JavaScript 模块</a>,并且默认情况下会被延迟。</p> + +<h3 id="CSS"> CSS</h3> + +<p>默认情况下,CSS被视为<a href="https://developer.mozilla.org/zh-CN/docs/Web/Performance/Critical_rendering_path">渲染阻塞</a>资源,因此,在 <a href="https://developer.mozilla.org/zh-CN/docs/Web/API/CSS_Object_Model">CSSOM</a> 被构造完成之前,浏览器不会渲染任何已处理的内容。CSS 必须很薄,才能尽快交付,建议使用媒体类型和查询实现非阻塞渲染。</p> + +<pre class="notranslate"><link href="style.css" rel="stylesheet" media="all"> +<link href="portrait.css" rel="stylesheet" media="orientation:portrait"> +<link href="print.css" rel="stylesheet" media="print"> +</pre> + +<p>可以执行一些 <a href="/zh-CN/docs/Learn/Performance/CSS">CSS 优化</a>来实现这一目标。</p> + +<h3 id="Fonts">Fonts</h3> + +<p>默认情况下,字体请求会延迟到构造渲染树之前,这可能会导致文本渲染延迟。</p> + +<p>It is possible to override the default behaviour and preload web font resources using <code><link rel="preload"></code>, the <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display">CSS font-display property</a>, and the <a href="https://developer.mozilla.org/en-US/docs/Web/API/CSS_Font_Loading_API">Font Loading API</a>.<br> + <br> + See also: <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link">Element Link</a></p> + +<h3 id="Images_and_iframes">Images and iframes</h3> + +<p>Very often, webpages contain many images that contribute to data-usage and how fast a page can load. Most of those images are off-screen (<a href="https://developer.mozilla.org/en-US/docs/Web/Performance/Critical_rendering_path">non-critical</a>), requiring user interaction (an example being scroll) in order to view them.</p> + +<p><strong>Loading </strong>属性<br> + The {{htmlattrxref("loading", "img")}} attribute on an {{HTMLElement("img")}} element (or the {{htmlattrxref("loading", "iframe")}} attribute on an {{HTMLElement("iframe")}}) can be used to instruct the browser to defer loading of images/iframes that are off-screen until the user scrolls near them.</p> + +<pre class="notranslate"><img src="image.jpg" alt="..." loading="lazy"> +<iframe src="video-player.html" title="..." loading="lazy"></iframe></pre> + +<p>The <code>load</code> event fires when the eagerly-loaded content has all been loaded; at that time, it's entirely possible (or even likely) that there may be lazily-loaded images that are within the {{Glossary("visual viewport")}} that haven't yet loaded.</p> + +<p>You can determine if a given image has finished loading by examining the value of its Boolean {{domxref("HTMLImageElement.complete", "complete")}} property.</p> + +<p><strong>Polyfill</strong><br> + Include this polyfill to provide support for older and currently incompatible browsers:<br> + <a href="https://github.com/mfranzke/loading-attribute-polyfill" rel="noopener">loading-attribute-polyfill</a></p> + +<p><strong>交叉观察者 API</strong><br> + <a href="https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver">Intersection Observers</a> allow the user to know when an observed element enters or exits the browser’s viewport.</p> + +<p><strong>事件处理程序</strong><br> + 当浏览器的兼容性至关重要时,有以下几种选择:</p> + +<ul> + <li><a href="https://github.com/w3c/IntersectionObserver">polyfill intersection observer</a></li> + <li>后退以滚动,调整大小或改变方向的事件处理程序,以确定特定元素是否在视口中</li> +</ul> + +<h2 id="规范">规范</h2> + +<table class="standard-table"> + <thead> + <tr> + <th><strong>Specification</strong></th> + <th><strong>Status</strong></th> + <th><strong>Comment</strong></th> + </tr> + </thead> + <tbody> + <tr> + <td>{{SpecName('HTML WHATWG', "#lazy-loading-attributes")}}</td> + <td>{{Spec2('HTML WHATWG')}}</td> + <td></td> + </tr> + </tbody> +</table> + +<h2 id="查看更多">查看更多</h2> + +<ul> + <li><a href="https://developers.google.com/web/fundamentals/performance/critical-rendering-path/render-blocking-css">Render blocking CSS</a></li> + <li><a href="https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/webfont-optimization#optimizing_loading_and_rendering">Optimizing loading and rendering</a></li> + <li><a href="https://developers.google.com/web/fundamentals/performance/lazy-loading-guidance/images-and-video">Lazy loading images and video</a></li> +</ul> + +<dl> +</dl> + +<div id="gtx-trans" style="position: absolute; left: 160px; top: 2955px;"> +<div class="gtx-trans-icon"></div> +</div> diff --git a/files/zh-cn/web/performance/optimizing_startup_performance/index.html b/files/zh-cn/web/performance/optimizing_startup_performance/index.html new file mode 100644 index 0000000000..4db51e5b7b --- /dev/null +++ b/files/zh-cn/web/performance/optimizing_startup_performance/index.html @@ -0,0 +1,97 @@ +--- +title: 优化启动性能 +slug: Web/Performance/Optimizing_startup_performance +tags: + - 应用 + - 性能 + - 游戏 +translation_of: Web/Performance/Optimizing_startup_performance +--- +<div class="summary"> +<p>一个在软件应用开发中经常被忽视的方面—即便在那些专注于性能优化的软件中—就是启动时的表现。你的应用需要花费多长时间启动?当应用加载时是否会卡住用户的设备或浏览器?这会让用户担心你的应用崩溃了,或者哪儿出错了。花时间确保你的应用能够更好地启动总是一个好主意。这篇文章提供了一些技巧和建议来帮助你达成这个目标,不管是在写一个新的应用还是从其他平台向Web移植一个应用。</p> +</div> + +<h2 id="更好地启动">更好地启动</h2> + +<p>不论在什么平台上,尽可能<strong>快</strong>地启动总是一个好主意。因为这是个很宽泛的问题,在这里我们不会着重关注。相反我们会关注构建 Web 应用时更重要的一个问题:尽可能<strong>异步地</strong>启动。这意味着不要将你所有的启动代码在应用主线程中的唯一一个事件处理函数中运行。</p> + +<p>相反,你应该这样写你的代码,让你的应用在后台线程创建一个 <a href="/en-US/docs/DOM/Using_web_workers" title="/en-US/docs/DOM/Using_web_workers">Web worker</a> ,做尽可能多的工作(比如,获取和处理数据)。然后,所有必须在主线程中完成的事情(比如用户事件和渲染用户界面)应该被分成小的片段,这样,当应用启动时,应用的事件循环就可以持续地运行下去。这可以避免应用、浏览器以及/或者设备出现锁死。</p> + +<p>为什么异步性很重要?除了上面提出的原因,还考虑了无响应页面或用户界面的影响。如果用户错误地启动了应用,将不能取消。如果应用正在浏览器中运行,用户可能会收到一个“应用无响应”或“加载缓慢”的提醒。你应该显示几种界面,比如进度条,这样用户可以在应用启动时知道他们需要等待多长时间。</p> + +<h2 id="如果有这样的打算...">如果有这样的打算...</h2> + +<p>如果你从头开始你的项目,通常很容易把所有的东西都写成“正确的方式”,使得代码片段具有合适的异步性。所有纯粹在启动时的计算应该在后台线程中执行,同时使主线程事件的运行时间尽可能缩短。应包含进度指示器,以便用户知道发生了什么以及他们将要等待多久。从理论上来说,无论如何,设计新的应用程序并能很好地启动应该很容易。</p> + +<p>但是,另一方面,当您将现有应用程序移植到Web上时,问题会变得棘手。桌面应用程序不需要以异步方式编写,因为通常操作系统会为您处理该问题;或者应用程序当前是唯一正在运行的主要任务,而这具体取决于操作环境。源程序可能有一个主循环,可以被轻松地改成异步操作(通过分别运行每个主循环);启动通常只是一个持续的整体过程,过程中可能会定期更新进度表。</p> + +<p>虽然您可以使用 <a href="/zh-CN/docs/Web/API/Web_Workers_API" title="/zh-CN/docs/Web/API/Web_Workers_API">Web workers</a> 异步运行体积巨大,持续时间长的 <a href="/zh-CN/docs/JavaScript" title="/zh-CN/docs/JavaScript">JavaScript</a> 代码块,但还是要给出一个重大警告:workers 不具备访问 <a href="/zh-CN/docs/WebGL" title="/zh-CN/docs/WebGL">WebGL</a> 或音频的能力,亦不能向主线程发送同步消息,所以你甚至不能将这些 API 代理到主线程中。所有的这一切意味着,除非你够轻松地抽取启动过程中的“纯计算”代码块,加入到 workers 中,否则你最后还是得在主线程上运行大部分或全部的启动代码。</p> + +<p>但是即便是那样的代码,通过一点点工作,也可以变为异步的。</p> + +<h2 id="异步化">异步化</h2> + +<p>关于如何构建你的启动过程,使得其尽可能异步执行,这里有些建议。(不过是新应用还是移植的):</p> + +<ul> + <li>启动时,在需要异步执行的脚本标签上使用 {{ htmlattrxref("defer") }} 或 {{ htmlattrxref("async") }} 属性 。这会允许 HTML 解析器更高效地处理文档。 <a href="/en-US/docs/Games/Techniques/Async_scripts">Async scripts for asm.js</a> 中有更多关于这方面的信息。</li> + <li>如果你需要解码资源文件(比如,解码JPEG文件并将其转换为原始纹理数据,以便随后在 WebGL 中使用),最好在 workers 里做这件事。</li> + <li>当处理浏览器支持的数据格式时(例如,解析图像数据),使用设备或浏览器内置的解码器而不是运行你自己的或者使用 or using one from the original codebase。预先提供的那个基本上一定会快得多,并且能够减小你的应用的启动体积。另外,浏览器可以自动并行化这些解码器的工作。</li> + <li>所有能并行的数据处理都应该并行化。不要一团接一团地处理数据,如果可能的话,同时处理它们! </li> + <li>在你启动的HTML文件中,不要包含不会在关键路径下出现的脚本或样式表。只在需要时加载他们。 </li> + <li>不要强迫 Web 引擎构建不需要的 DOM,一种简单的“hack”的方式是把你的HTML留在文档里,但是在外层包裹注释。 + <pre><div id="foo"><!-- + <div> ... +--></div></pre> + </li> + <li>当文档的一部分需要被渲染时,加载被注释的HTML + <pre>foo.innerHTML = foo.firstChild.nodeValue;</pre> + </li> +</ul> + +<p>你能通过异步的方式做的事越多,应用就能更好的利用多核处理器。</p> + +<h3 id="移植问题">移植问题</h3> + +<p>一旦初始加载完成,应用的主程序开始运行,有可能你的应用一定会是单线程的,尤其当它是个移植的程序时。尝试改善主程序的启动过程时,最重要的事情是将代码重构为小片段。这些小片段可以在你应用的主循环中通过多个调用在分散的代码段中执行,这样主线程就能处理输入和类似的事件。</p> + +<p>Emscripten 提供了一个API 帮助处理这种重构;比如你可以用 <code>emscripten_push_main_loop_blocker()</code> 创建一个函数,在主线程可以继续运行前执行。通过创建一个可以依序调用的函数队列,你可以更轻松地在不阻塞主线程地情况下管理代码的运行。</p> + +<p>但是这留下了不得不重构现有代码,使程序真正这样运行的问题。这可能需要一些时间。</p> + +<h3 id="我究竟要异步化到什么程度?">我究竟要异步化到什么程度?</h3> + +<p>最好记住大多数浏览器,在你的代码阻塞主线程太长时间——大约10秒左右的时候,就会开始抱怨。理想情况下,你不会在任何地方阻塞那么长时间,但是只要你把时间保持在这之下,就不会有问题。不过要记住,如果有人有个比你更旧更慢的电脑,他们或许会比你经历更长的等待!</p> + +<h2 id="其他建议">其他建议</h2> + +<p>除了异步化之外,还有一些其他的事情,可以帮助你改善应用启动时间。这是其中的一部分:</p> + +<dl> + <dt>下载时间</dt> + <dd>一定要记住用户需要花多少时间下载你游戏的数据。如果你的游戏非常大,很受欢迎,或者需要频繁的重下内容,你应该考虑买个速度越快越好托管服务器。你还应该考虑压缩数据,尽可能缩小其体积。</dd> + <dt>GPU因素</dt> + <dd>编译着色器,以及将纹理传输到 GPU 会占用时间,特别是在比较复杂的游戏中。尽管这也会发生在本地(非 Web ) 游戏中,但还是会很恼人。不要不告诉用户游戏实际上还在启动中就这么做。</dd> + <dt>数据大小</dt> + <dd>尽力优化游戏数据的体积,小一些的文件下载和处理都比大文件快。</dd> + <dt>主观因素</dt> + <dd>你可以在启动过程中做一些事情来使用户专注于其上,这会让时间看起来过得更快些。 就游戏而言,可以考虑播放一些背景音乐或者显示漂亮的启动画面;在运算执行期间,更新你的进度提示,改变显示内容,或者做任何你想做的事情:这有助于用户知晓应用正在做一些工作,而不是一声不吭地呆在那儿。</dd> +</dl> + +<h2 id="相关链接">相关链接</h2> + +<ul> + <li><a href="/en-US/docs/Apps" title="/en-US/docs/Apps">Apps</a></li> + <li><a href="/en-US/docs/Games" title="/en-US/docs/Games">Games</a></li> +</ul> + +<div class="originaldocinfo"> +<h2 id="Original_Document_Information" name="Original_Document_Information">原文档信息</h2> + +<ul> + <li>作者: Alon Zakai</li> + <li>源链接: <a href="http://mozakai.blogspot.com/2012/07/bananabread-or-any-compiled-codebase.html" title="http://mozakai.blogspot.com/2012/07/bananabread-or-any-compiled-codebase.html">BananaBread (or any compiled codebase) Startup Experience</a></li> +</ul> +</div> + +<p> </p> diff --git a/files/zh-cn/web/performance/rum-vs-synthetic/index.html b/files/zh-cn/web/performance/rum-vs-synthetic/index.html new file mode 100644 index 0000000000..efb435766b --- /dev/null +++ b/files/zh-cn/web/performance/rum-vs-synthetic/index.html @@ -0,0 +1,38 @@ +--- +title: 'Performance Monitoring: RUM vs synthetic monitoring' +slug: Web/Performance/Rum-vs-Synthetic +tags: + - RUM + - Synthetic monitoring + - Web Performance +translation_of: Web/Performance/Rum-vs-Synthetic +--- +<p><span class="seoSummary"><strong>综合监控</strong>和<strong>真实用户监控</strong> (RUM) </span>是两种监视和提供 Web性能见解的方法。RUM and synthetic monitoring provide for different views of performance and have benefits, good use cases and shortfalls. RUM is generally best suited for understanding long-term trends whereas synthetic monitoring is very well suited to regression testing and mitigating shorter-term performance issues during development.<span class="seoSummary"> In this article we define and compare these two performance monitoring approaches.</span></p> + +<h2 id="合成监控"><strong>合成</strong>监控</h2> + +<p>Synthetic monitoring involves monitoring the performance of a page in a 'laboratory' environment, typically with automation tooling in a consistent as possible environment. Synthetic Monitoring involves deploying scripts to simulate the path an end user might take through a web application, reporting back the performance the simulator experiences. The traffic measured is not of your actual users, but rather synthetically generated traffic collecting data on page performance.</p> + +<p>An example of synthetic monitoring is <a href="https://WebPageTest.org">WebPageTest.org</a>. It is done in a controlled environment where variable like geography, network, device, browser, and cached status are predetermined. It provides waterfall charts for every asset served by the host and <a href="/en-US/docs/Glossary/CDN">CDN</a> as well as every third party asset and asset requests generated by all third party scripts, such as ads and analytic services.</p> + +<p>Controlling for environmental variables is helpful in understanding where performance bottlenecks have been occurring and identifying the source of any performance issues. For example, but it isn't reflective of the actual experience of users, especially the long tail.</p> + +<p>Synthetic monitoring can be an important component of regression testing and production site monitoring. Test the site at every stage of development and regularly in production. Changes from baseline performance as part of continuous integration should fail a push. If an issue arises in production, synthetic monitoring can provide insight, helping identify, isolate, and resolve problems before they negatively user experience.</p> + +<h2 id="真实用户监控">真实用户监控</h2> + +<p id="Real_User_Monitoring_(RUM)"><strong>Real User Monitoring</strong> or<strong> </strong>RUM measures the performance of a page from real users' machines. Generally, a third party script injects a script on each page to measure and report back on page load data for every request made. This technique monitors an application’s actual user interactions. In real user monitoring, the browsers of real users report back performance metrics experienced. RUM helps identify how an application is being used, including the geographic distribution of users and the impact of that distribution on the end user experience.</p> + +<p>Unlike Synthetic monitoring, RUM captures the performance of actual users regardless of device, browser, network or geographic location. As users interact with an application, all performance timings are captured, regardless of what actions are taken or pages viewed. RUM monitors actual use cases, not the synthetic, assumed use cases predefined by an engineer, PM, or marketing team. This is particularly important for large sites or complex apps, where the functionality or content is constantly changing, and where the population accessing the application may differ greatly in life experiences from those creating it.</p> + +<p>By leveraging RUM, a business can better understand its users and identify the areas on its site that require the most attention. Moreover, RUM can help to understand the geographic or channel distribution trends of your users. Knowing your user trends helps you better define your business plan and, from a monitoring perspective, allows you to identify key areas to target for optimization and performance improvements.</p> + +<h2 id="RUM_vs_Synthetic">RUM vs Synthetic</h2> + +<p>Synthetic is well suited for catching regressions during development life cycles, especially with {{glossary('network throttling')}}. It is fairly easy, inexpensive, and great for spot-checking performance during development as an effective way to measure the effect of code changes, but it doesn’t reflect what real users are experiencing and provides only a narrow view of performance.</p> + +<p>RUM, on the other hand, provides real metrics from real users using the site or application. While this is more expensive and likely less convenient, it provides vital user experience data.</p> + +<h2 id="性能_APIs">性能 APIs</h2> + +<p>There are many monitoring services. If you do want to roll your own monitoring system, take a look at the performance APIs, mainly {{domxref("PerformanceNavigationTiming")}} and {{domxref("PerformanceResourceTiming")}}, but also {{domxref("PerformanceMark")}}, {{domxref("PerformanceMeasure")}}, and {{domxref("PerformancePaintTiming")}}.</p> diff --git a/files/zh-cn/web/performance/浏览器渲染页面的工作原理/index.html b/files/zh-cn/web/performance/浏览器渲染页面的工作原理/index.html new file mode 100644 index 0000000000..71e4bce57e --- /dev/null +++ b/files/zh-cn/web/performance/浏览器渲染页面的工作原理/index.html @@ -0,0 +1,204 @@ +--- +title: 渲染页面:浏览器的工作原理 +slug: Web/Performance/浏览器渲染页面的工作原理 +translation_of: Web/Performance/How_browsers_work +--- +<p>页面内容快速加载和流畅的交互是用户希望得到的Web体验,因此,开发者应力争实现这两个目标。</p> + +<p><span class="seoSummary">了解如何提升性能和感知性能,有助于了解浏览器的工作原理。</span></p> + +<h2 id="概述">概述</h2> + +<p>快速响应的网站提供更好的用户体验。用户期待内容快速加载和交互流畅的Web体验</p> + +<p>等待资源加载时间和大部分情况下的浏览器单线程执行是影响Web性能的两大主要原因。</p> + +<p>等待时间是需要去克服来让浏览器快速加载资源的主要威胁. 为了实现快速加载,开发者的目标就是尽可能快的发送请求的信息,至少看起来相当快。网络等待时间是在链路上传送二进制到电脑端所消耗的链路传输时间。 Web性能优化需要做的就是尽可能快的使页面加载完成。</p> + +<p>大部分情况下,浏览器是单线程执行的。为了有流畅的交互 ,开发者的目标是确保网站从流畅的页面滚动到点击响应的交互性能。渲染时间是关键要素,确保主线程可以完成所有给它的任务并且仍然一直可以处理用户的交互。通过了解浏览器单线程的本质与最小化主线程的责任可以优化Web性能,来确保渲染的流畅和交互响应的及时。</p> + +<h2 id="导航">导航</h2> + +<p><em></em>导航是加载web页面的第一步。它发生在以下情形:用户通过在地址栏输入一个URL、点击一个链接、提交表单或者是其他的行为</p> + +<p>web性能优化的目标之一就是缩短导航完成所花费的时间,在理想情况下,它通常不会花费太多的时间,但是等待时间和带宽会导致它的延时。</p> + +<h3 id="DNS_查找">DNS 查找</h3> + +<p>对于一个web页面来说导航的第一步是要去寻找页面资源的位置。如果导航到<code>https://example.com</code>, HTML页面 被定为到IP地址为 <code>93.184.216.34</code> 的服务器。如果以前没有访问过这个网站,就需要进行DNS查找。</p> + +<p>浏览器通过服务器名称请求DNS进行查找,最终返回一个IP地址,第一次初始化请求之后,这个IP地址可能会被缓存一段时间,这样可以通过从缓存里面检索IP地址而不是再通过域名服务器进行查找来加速后续的请求</p> + +<p>通过主机名加载一个页面通常仅需要DNS查找一次.。但是, DNS需要对不同的页面指向的主机名进行查找。如果fonts, images, scripts, ads, and metrics 都不同的主机名,DNS会对每一个进行查找。</p> + +<p><img alt="Mobile requests go first to the cell tower, then to a central phone company computer before being sent to the internet" src="https://mdn.mozillademos.org/files/16743/latency.jpg" style="height: 281px; width: 792px;"></p> + +<p>DNS查找对于性能来说是一个问题,特别是对于移动网络。当一个用户用的是移动网络,每一个DNS查找必须从手机发送到信号塔,然后到达一个认证DNS服务器。手机、信号塔、域名服务器之间的距离可能是一个大的时间等待。</p> + +<h3 id="TCP_Handshake">TCP Handshake</h3> + +<p>一旦获取到服务器IP地址,浏览器就会通过TCP”三次握手“与服务器建立连接。这个机制的是用来让两端尝试进行通信—浏览器和服务器在发送数据之前,通过上层协议Https可以协商网络TCP套接字连接的一些参数。</p> + +<p>TCP的”三次握手“技术经常被称为”SYN-SYN-ACK“—更确切的说是 SYN, SYN-ACK, ACK—因为通过TCP首先发送了三个消息进行协商,开始一个TCP会话在两台电脑之间。 是的,这意味着每台服务器之间还要来回发送三条消息,而请求尚未发出。</p> + +<h3 id="TLS_协商">TLS 协商</h3> + +<p>为了在HTTPS上建立安全连接,另一种握手是必须的。更确切的说是TLS协商 ,它决定了什么密码将会被用来加密通信,验证服务器,在进行真实的数据传输之前建立安全连接。在发送真正的请求内容之前还需要三次往返服务器。</p> + +<p><img alt="The DNS lookup, the TCP handshake, and 5 steps of the TLS handshake including clienthello, serverhello and certificate, clientkey and finished for both server and client." src="https://mdn.mozillademos.org/files/16746/ssl.jpg" style="height: 412px; width: 729px;"></p> + +<p>虽然建立安全连接对增加了加载页面的等待时间,对于建立一个安全的连接来说,以增加等待时间为代价是值得的,因为在浏览器和web服务器之间传输的数据不可以被第三方解密。</p> + +<p>经过8次往返,浏览器终于可以发出请求。</p> + +<h2 id="响应">响应</h2> + +<p>一旦我们建立了到web服务器的连接,浏览器就代表用户发送一个初始的HTTP GET请求,对于网站来说,这个请求通常是一个HTML文件。 一旦服务器收到请求,它将使用相关的响应头和HTML的内容进行回复。</p> + +<pre class="brush: html"><!doctype HTML> +<html> + <head> + <meta charset="UTF-8"/> + <title>My simple page</title> + <link rel="stylesheet" src="styles.css"/> + <script src="myscript.js"></script> +</head> +<body> + <h1 class="heading">My Page</h1> + <p>A paragraph with a <a href="https://example.com/about">link</a></p> + <div> + <img src="myimage.jpg" alt="image description"/> + </div> + <script src="anotherscript.js"></script> +</body> +</html></pre> + +<p>初始请求的响应包含所接收数据的第一个字节。”Time to First Byte“ (TTFB)是用户通过点击链接进行请求与收到第一个HTML包之间的时间。第一块内容通常是14kb的数据。</p> + +<p>上面的例子中,这个请求肯定是小于14kb的,但是直到浏览器在解析阶段遇到链接时才会去请求链接的资源,下面有进行描述。</p> + +<h3 id="TCP_慢开始_14kb_规则">TCP 慢开始 / 14kb 规则</h3> + +<p>第一个响应包是14kb大小。这是慢开始的一部分,慢开始是一种均衡网络连接速度的算法。慢开始逐渐增加发送数据的数量直到达到网络的最大带宽。</p> + +<p>在"TCP slow start"中,在收到初始包之后, 服务器会将下一个包的大小加倍到大约28kb。 后续的包依次是前一个包大小的二倍直到达到预定的阈值,或者遇到拥塞。</p> + +<p><img alt="TCP slow start" src="https://mdn.mozillademos.org/files/16754/congestioncontrol.jpg" style="height: 412px; width: 729px;"></p> + +<p>如果您听说过初始页面加载的14Kb规则,TCP慢开始就是初始响应为14Kb的原因,也是为什么web性能优化需要将此初始14Kb响应作为优化重点的原因。TCP慢开始逐渐建立适合网络能力的传输速度,以避免拥塞。</p> + +<h3 id="拥塞控制">拥塞控制</h3> + +<p><span style="font-weight: 400;">当服务器用TCP包来发送数据时,客户端通过返回确认帧来确认传输。由于硬件和网络条件,连接的容量是有限的。 如果服务器太快地发送太多的包,它们可能会被丢弃。意味着,将不会有确认帧的返回。服务器把它们当做确认帧丢失。拥塞控制算法使用这个发送包和确认帧流来确定发送速率。</span></p> + +<h2 id="解析">解析</h2> + +<p>一旦浏览器收到数据的第一块,它就可以开始解析收到的信息。“推测性解析”,“解析”是浏览器将通过网络接收的数据转换为DOM和CSSOM的步骤,通过渲染器把DOM和CSSOM在屏幕上绘制成页面。</p> + +<p>DOM是浏览器标记的内部表示。DOM也是被暴露的,可以通过JavaScript中的各种API进行DOM操作。</p> + +<p>即使请求页面的HTML大于初始的14KB数据包,浏览器也将开始解析并尝试根据其拥有的数据进行渲染。这就是为什么在前14Kb中包含浏览器开始渲染页面所需的所有内容,或者至少包含页面模板(第一次渲染所需的CSS和HTML)对于web性能优化来说是重要的。但是在渲染到屏幕上面之前,HTML、CSS、JavaScript必须被解析完成。</p> + +<h3 id="构建DOM树">构建DOM树</h3> + +<p>我们描述五个步骤在这篇文章中 <a href="/en-US/docs/Web/Performance/Critical_rendering_path">critical rendering path</a>.</p> + +<p>第一步是处理HTML标记并构造DOM树。HTML解析涉及到 <a href="/en-US/docs/Web/API/DOMTokenList">tokenization</a> 和树的构造。HTML标记包括开始和结束标记,以及属性名和值。 如果文档格式良好,则解析它会简单而快速。解析器将标记化的输入解析到文档中,构建文档树。</p> + +<p>DOM树描述了文档的内容。<html>元素是第一个标签也是文档树的根节点。树反映了不同标记之间的关系和层次结构。嵌套在其他标记中的标记是子节点。DOM节点的数量越多,构建DOM树所需的时间就越长。</p> + +<p><img alt="The DOM tree for our sample code, showing all the nodes, including text nodes." src="https://mdn.mozillademos.org/files/16759/DOM.gif" style="height: 689px; width: 754px;"></p> + +<p>当解析器发现非阻塞资源,例如一张图片,浏览器会请求这些资源并且继续解析。当遇到一个CSS文件时,解析也可以继续进行,但是对于<script>标签(特别是没有 <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/async_function">async</a></code> 或者 <code>defer</code> 属性)会阻塞渲染并停止HTML的解析。尽管浏览器的预加载扫描器加速了这个过程,但过多的脚本仍然是一个重要的瓶颈。</p> + +<h3 id="预加载扫描器">预加载扫描器</h3> + +<p>浏览器构建DOM树时,这个过程占用了主线程。当这种情况发生时,预加载扫描仪将解析可用的内容并请求高优先级资源,如CSS、JavaScript和web字体。多亏了预加载扫描器,我们不必等到解析器找到对外部资源的引用来请求它。它将在后台检索资源,以便在主HTML解析器到达请求的资源时,它们可能已经在运行,或者已经被下载。预加载扫描仪提供的优化减少了阻塞。</p> + +<pre class="brush:html"><link rel="stylesheet" src="styles.css"/> +<script src="myscript.js" <strong>async</strong>></script> +<img src="myimage.jpg" alt="image description"/> +<script src="anotherscript.js" <strong>async</strong>></script> +</pre> + +<p>在这个例子中,当主线程在解析HTML和CSS时,预加载扫描器将找到脚本和图像,并开始下载它们。为了确保脚本不会阻塞进程,当JavaScript解析和执行顺序不重要时,可以添加async属性或defer属性。</p> + +<p>等待获取CSS不会阻塞HTML的解析或者下载,但是它的确阻塞JavaScript,因为JavaScript经常用于查询元素的CSS属性。</p> + +<h3 id="构建CSSOM树">构建CSSOM树</h3> + +<p>第二步是处理CSS并构建CSSOM树。CSS对象模型和DOM是相似的。<span style="color: #212121; display: inline !important; float: none; font-family: Roboto,sans-serif; font-size: 16px; font-style: normal; font-weight: 400; letter-spacing: normal; text-align: left; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;">DOM和CSSOM是两棵树. 它们是独立的数据结构。浏览器将CSS规则转换为可以理解和使用的样式映射。浏览器遍历CSS中的每个规则集,根据CSS选择器创建具有父、子和兄弟关系的节点树。</span></p> + +<p>与HTML一样,浏览器需要将接收到的CSS规则转换为可以使用的内容。因此,它重复了HTML到对象的过程,但对于CSS。</p> + +<p>CSSOM树包括来自用户代理样式表的样式。浏览器从适用于节点的最通用规则开始,并通过应用更具体的规则递归地优化计算的样式。换句话说,它级联属性值。</p> + +<p>构建CSSOM非常非常快,并且在当前的开发工具中没有以独特的颜色显示。相反,开发人员工具中的“重新计算样式”显示解析CSS、构造CSSOM树和递归计算计算样式所需的总时间。在web性能优化方面,它是可轻易实现的,因为创建CSSOM的总时间通常小于一次DNS查找所需的时间。</p> + +<h3 id="其他过程">其他过程</h3> + +<h4 id="JavaScript_编译">JavaScript 编译</h4> + +<p>当CSS被解析并创建CSSOM时,其他资源,包括JavaScript文件正在下载(多亏了preload scanner)。JavaScript被解释、编译、解析和执行。脚本被解析为抽象语法树。一些浏览器引擎使用”Abstract Syntax Tree“并将其传递到解释器中,输出在主线程上执行的字节码。这就是所谓的JavaScript编译。</p> + +<h4 id="构建辅助功能树">构建辅助功能树</h4> + +<p>浏览器还构建辅助设备用于分析和解释内容的辅助功能(<a href="/en-US/docs/Learn/Accessibility">accessibility</a> )树。可访问性对象模型(AOM)类似于DOM的语义版本。当DOM更新时,浏览器会更新辅助功能树。辅助技术本身无法修改可访问性树。</p> + +<p>在构建AOM之前,屏幕阅读器(<a href="/en-US/docs/Web/Accessibility/ARIA/ARIA_Screen_Reader_Implementors_Guide">screen readers</a>)无法访问内容。</p> + +<h2 id="渲染">渲染</h2> + +<p>渲染步骤包括样式、布局、绘制,在某些情况下还包括合成。在解析步骤中创建的CSSOM树和DOM树组合成一个Render树,然后用于计算每个可见元素的布局,然后将其绘制到屏幕上。在某些情况下,可以将内容提升到它们自己的层并进行合成,通过在GPU而不是CPU上绘制屏幕的一部分来提高性能,从而释放主线程。</p> + +<h3 id="Style">Style</h3> + +<p>第三步是将DOM和CSSOM组合成一个Render树,计算样式树或渲染树从DOM树的根开始构建,遍历每个可见节点。</p> + +<p>像<head>和它的子节点以及任何具有<code>display: none</code>样式的结点,例如<code>script { display: none; }</code>(在user agent stylesheets可以看到这个样式)这些标签将不会显示,也就是它们不会出现在Render树上。具有<code>visibility: hidden</code>的节点会出现在Render树上,因为它们会占用空间。由于我们没有给出任何指令来覆盖用户代理默认值,因此上面代码示例中的script节点将不会包含在Render树中。</p> + +<p>每个可见节点都应用了其CSSOM规则。Render树保存所有具有内容和计算样式的可见节点——将所有相关样式匹配到DOM树中的每个可见节点,并根据CSS级联确定每个节点的计算样式。</p> + +<h3 id="Layout">Layout</h3> + +<p>第四步是在渲染树上运行布局以计算每个节点的几何体。布局是确定呈现树中所有节点的宽度、高度和位置,以及确定页面上每个对象的大小和位置的过程。回流是对页面的任何部分或整个文档的任何后续大小和位置的确定。</p> + +<p>构建渲染树后,开始布局。渲染树标识显示哪些节点(即使不可见)及其计算样式,但不标识每个节点的尺寸或位置。为了确定每个对象的确切大小和位置,浏览器从渲染树的根开始遍历它。</p> + +<p>在网页上,大多数东西都是一个盒子。不同的设备和不同的桌面意味着无限数量的不同的视区大小。在此阶段,考虑到视区大小,浏览器将确定屏幕上所有不同框的尺寸。以视区的大小为基础,布局通常从body开始,用每个元素的框模型属性排列所有body的子孙元素的尺寸,为不知道其尺寸的替换元素(例如图像)提供占位符空间。</p> + +<p>第一次确定节点的大小和位置称为布局。随后对节点大小和位置的重新计算称为回流。在我们的示例中,假设初始布局发生在返回图像之前。由于我们没有声明图像的大小,因此一旦知道图像大小,就会有回流。</p> + +<h3 id="Paint">Paint</h3> + +<p>最后一步是将各个节点绘制到屏幕上,第一次出现的节点称为<a href="/en-US/docs/Glossary/first_meaningful_paint">first meaningful paint</a>。在绘制或光栅化阶段,浏览器将在布局阶段计算的每个框转换为屏幕上的实际像素。绘画包括将元素的每个可视部分绘制到屏幕上,包括文本、颜色、边框、阴影和替换的元素(如按钮和图像)。浏览器需要非常快地完成这项工作。</p> + +<p>为了确保平滑滚动和动画,占据主线程的所有内容,包括计算样式,以及回流和绘制,必须让浏览器在16.67毫秒内完成。在2048x 1536,iPad有超过314.5万像素将被绘制到屏幕上。那是很多像素需要快速绘制。为了确保重绘的速度比初始绘制的速度更快,屏幕上的绘图通常被分解成数层。如果发生这种情况,则需要进行合成。</p> + +<p>绘制可以将布局树中的元素分解为多个层。将内容提升到GPU上的层(而不是CPU上的主线程)可以提高绘制和重新绘制性能。有一些特定的属性和元素可以实例化一个层,包括<video>和<canvas>,任何CSS属性为opacity、3D转换、<code><a href="/en-US/docs/Web/CSS/will-change">will-change</a></code>的元素,还有一些其他元素。这些节点将与子节点一起绘制到它们自己的层上,除非子节点由于上述一个(或多个)原因需要自己的层。</p> + +<p>层确实可以提高性能,但是它以内存管理为代价,因此不应作为web性能优化策略的一部分过度使用。</p> + +<h3 id="Compositing">Compositing</h3> + +<p>当文档的各个部分以不同的层绘制,相互重叠时,必须进行合成,以确保它们以正确的顺序绘制到屏幕上,并正确显示内容。</p> + +<p>当页面继续加载资产时,可能会发生回流(回想一下我们迟到的示例图像),回流会触发重新绘制和重新组合。如果我们定义了图像的大小,就不需要重新绘制,只需要重新绘制需要重新绘制的层,并在必要时进行合成。但我们没有包括图像大小!从服务器获取图像后,渲染过程将返回到布局步骤并从那里重新开始。</p> + +<h2 id="交互">交互</h2> + +<p>一旦主线程绘制页面完成,你会认为我们已经“准备好了”,但事实并非如此。如果加载包含JavaScript(并且延迟到<code><a href="/en-US/docs/Web/API/GlobalEventHandlers/onload">onload</a></code>事件激发后执行),则主线程可能很忙,无法用于滚动、触摸和其他交互。</p> + +<p>”Time to Interactive“(TTI)是测量从第一个请求导致DNS查找和SSL连接到页面可交互时所用的时间——可交互是”First Contentful Paint“之后的时间点,页面在50ms内响应用户的交互。如果主线程正在解析、编译和执行JavaScript,则它不可用,因此无法及时(小于50ms)响应用户交互。</p> + +<p>在我们的示例中,可能图像加载很快,但<code>anotherscript.js</code>文件可能是2 MB,而且用户的网络连接很慢。在这种情况下,用户可以非常快地看到页面,但是在下载、解析和执行脚本之前,就无法滚动。这不是一个好的用户体验。避免占用主线程,如下面的WebPageTest示例所示:</p> + +<p><img alt="The main thread is occupied by the downloading, parsing and execution of a javascript file - over a fast connection" src="https://mdn.mozillademos.org/files/16760/visa_network.png" style="height: 699px; width: 1200px;"></p> + +<p>在本例中,DOM内容加载过程花费了1.5秒多的时间,主线程在这段时间内完全被占用,对单击事件或屏幕点击没有响应。</p> + +<h2 id="See_Also">See Also</h2> + +<ul> + <li><a href="/en-US/docs/Web/Performance">Web Performance</a></li> +</ul> |