<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.6.0">Jekyll</generator><link href="/feed.xml" rel="self" type="application/atom+xml" /><link href="/" rel="alternate" type="text/html" /><updated>2017-10-21T04:46:26+00:00</updated><id>/</id><title type="html">Asjoy’s Blog</title><subtitle>just for web front-end sharing, mybe sometimes java. to be better together  
</subtitle><entry><title type="html">webkit 解析 webpage 的生命周期</title><link href="/webkit/performance/2017/01/24/webkit-wor-process.html" rel="alternate" type="text/html" title="webkit 解析 webpage 的生命周期" /><published>2017-01-24T02:59:45+00:00</published><updated>2017-01-24T02:59:45+00:00</updated><id>/webkit/performance/2017/01/24/webkit-wor-process</id><content type="html" xml:base="/webkit/performance/2017/01/24/webkit-wor-process.html">&lt;h2 id=&quot;webkit-简介&quot;&gt;webkit 简介&lt;/h2&gt;
&lt;p&gt;    首发于2003年的safari浏览器。WebKit的代码源自1998年所开发的KDE的HTML排版引擎KHTML及KDE的JavaScript引擎KJS的代码， 当时webkit仅为&lt;code class=&quot;highlighter-rouge&quot;&gt;khtml&lt;/code&gt;与&lt;code class=&quot;highlighter-rouge&quot;&gt;kjs&lt;/code&gt;的一个fork版本，将他们重新命名为 WebCore 及 JavaScriptCore。 之后因为各平台需要发展出不同的分支，像chromium，qtwebkit等&lt;/p&gt;

&lt;h2 id=&quot;webkit组成部分&quot;&gt;webkit组成部分&lt;/h2&gt;
&lt;p&gt;见下图：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/asset/img/webkit-diagram.png&quot; alt=&quot;webkit&quot; /&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;browser UI比如浏览器的书签栏搜索栏等&lt;/li&gt;
  &lt;li&gt;webkit Embedding API是webkit嵌入的api接口，browser UI通过webkit Embedding API与webpage进行交互。&lt;/li&gt;
  &lt;li&gt;webcore 负责webpage的资源的调度加载， 解析， cssobject model构建， dom解析与构建， 事件处理等&lt;/li&gt;
  &lt;li&gt;jacascriptCore 包括垃圾回收与解释器（将js语法转为二进制机器码）&lt;/li&gt;
  &lt;li&gt;platformAPI是提供与底层驱动的交互， 如网络， 字体渲染， 影音文件解码等， 渲染引擎（webkit将所有的render都交给platform处理， 值得一提的是不同的浏览器会选择不同的渲染引擎， 想chrome为了保持不同平台尽可能的一致，采用的是skia， 而安卓是完全交给android stack来处理的，这也是为什么不同款的安卓机展示的出的ui有些是不同的）&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;webkit工作流程&quot;&gt;webkit工作流程&lt;/h2&gt;
&lt;p&gt;具体流程见下图：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/asset/img/webkit-work-process.png&quot; alt=&quot;webkit work process&quot; /&gt;&lt;/p&gt;

&lt;p&gt;webkit的资源加载器对加载到的html，css，js分别解析。 后经过layout渲染出render tree， 经过绘制（paint），合成(composite) 最终输出到浏览器上，
我们简单对下面代码进行解析：&lt;/p&gt;

&lt;p&gt;index.html&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;meta&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;viewport&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;content=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;width=device-width,initial-scale=1&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;style.css&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;stylesheet&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Critical Path&lt;span class=&quot;nt&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Hello &lt;span class=&quot;nt&quot;&gt;&amp;lt;span&amp;gt;&lt;/span&gt;web performance&lt;span class=&quot;nt&quot;&gt;&amp;lt;/span&amp;gt;&lt;/span&gt; students!&lt;span class=&quot;nt&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&amp;gt;&amp;lt;img&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;awesome-photo.jpg&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;style.css&lt;/p&gt;

&lt;div class=&quot;language-css highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;16px&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;font-weight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;bold&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;span&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;red&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;span&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;none&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;right&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;htmlparser解析构建dom-tree&quot;&gt;htmlParser解析构建dom tree&lt;/h3&gt;

&lt;p&gt;dom解析需要经过以下步骤&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;转换：浏览器从磁盘或网络读取 HTML 的原始字节，然后根据指定的文件编码格式（例如 UTF-8）将其转换为相应字符。&lt;/li&gt;
  &lt;li&gt;符号化：浏览器将字符串转换为 W3C HTML5 标准 指定的各种符号 - 比如 ““、”” 及其他「尖括号」内的字符串。每个符号都有特殊含义并一套规则。&lt;/li&gt;
  &lt;li&gt;词法分析：发射的符号转换为「对象」，定义它们的属性与规则。&lt;/li&gt;
  &lt;li&gt;DOM 构建：最后，因为 HTML 标记定义不同标签间的相互关系（某些标签嵌套在其他标签中），所以创建的对象在树状数据结构中互相链接，树状数据结构还捕获原始标记中定义的父子关系：比如 HTML 对象是 body 对象的父对象，body 是 paragraph 对象的父对象等等。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src=&quot;/asset/img/webkit-work-dom.png&quot; alt=&quot;dom construction&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;cssparse解析成cssom树状结构&quot;&gt;cssParse解析成cssOM(树状结构)&lt;/h3&gt;
&lt;p&gt;与构建dom经过相同的步骤， 结果如下&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/asset/img/webkit-work-cssom.png&quot; alt=&quot;dom construction&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;经过layoutreflow构建出render-tree&quot;&gt;经过layout/reflow构建出render tree&lt;/h3&gt;
&lt;p&gt;大致步骤如下：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;从 DOM 树的根节点开始，遍历每个可见的节点。&lt;/li&gt;
  &lt;li&gt;某些节点完全不可见（例如 script 标签、meta 标签等），因为它们不会在渲染结果中反映，所以会被忽略。&lt;/li&gt;
  &lt;li&gt;某些节点通过 CSS 隐藏，因此在渲染树中也会被忽略。比方说，上面例子中的 span 节点，因为该节点有一条显式规则设置了 display:none 属性，所以不会出现在渲染树中。&lt;/li&gt;
  &lt;li&gt;给每个可见节点找到相应匹配的 CSSOM 规则，并应用这些规则。&lt;/li&gt;
  &lt;li&gt;发射可见节点，连带其内容及计算的样式。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;构建过程如下：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/asset/img/webkit-work-rendertree.png&quot; alt=&quot;dom construction&quot; /&gt;&lt;/p&gt;

&lt;p&gt;关于批量dom优化在layout/reflow过程可能产生的layout thrashing问题可以参考我的另一篇blog &lt;a href=&quot;/webkit/performance/2017/01/10/layout-thrashing.html&quot;&gt;DOM批量处理与 layout thrashing&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;paint过程简介-与-compsoite硬件加速&quot;&gt;paint过程简介 与 compsoite硬件加速&lt;/h2&gt;

&lt;h3 id=&quot;paint简介&quot;&gt;paint简介&lt;/h3&gt;
&lt;p&gt;由webkit工作流程图可知， 当我们触发layout层的时候(修改dom布局的几何属性时触发，具体参考我的另一篇blog &lt;a href=&quot;/webkit/performance/2017/01/10/layout-thrashing.html&quot;&gt;DOM批量处理与 layout thrashing&lt;/a&gt; ），必然会触发paint层或repaint层。触发一些非布局几何属性例如background, box-shdow等也会触发。paint过程是填充像素的过程，这些像素将最终显示在用户的屏幕上。通常这个过程是最消耗时长的一环。&lt;/p&gt;

&lt;p&gt;绘制过程并非单层绘制，而是多层绘制后并合并成渲染层，最后合并为一层。以下列出了产生新的渲染层的条件:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;3D 或透视变换(perspective transform) CSS 属性&lt;/li&gt;
  &lt;li&gt;使用加速视频解码的 元素&lt;/li&gt;
  &lt;li&gt;拥有 3D (WebGL) 上下文或加速的 2D 上下文的 元素&lt;/li&gt;
  &lt;li&gt;混合插件(如 Flash)&lt;/li&gt;
  &lt;li&gt;对自己的 opacity 做 CSS 动画或使用一个动画 webkit 变换的元素&lt;/li&gt;
  &lt;li&gt;拥有加速 CSS 过滤器的元素&lt;/li&gt;
  &lt;li&gt;元素有一个包含复合层的后代节点(换句话说，就是一个元素拥有一个子元素，该子元素在自己的层里)&lt;/li&gt;
  &lt;li&gt;元素有一个 z-index 较低且包含一个复合层的兄弟元素(换句话说就是该元素在复合层上面渲染)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;默认渲染层是使用GPU加速的，就意味着当cpu计算完成paint过程之后会传给gpu存储，处理。我们知道gpu擅长图片处理尤其是一些&lt;strong&gt;matrix的变换&lt;/strong&gt;，translate， skew， alpha等。第一次时cpu计算完成传给gpu处理后改变下次变化matrix的变化不需要触发paint/repaint过程，直接触发composite过程即可，这样就避免了repain的大量的冗余的计算。
具体过程可以通过如下:&lt;/p&gt;

&lt;p&gt;最好方式就是使用CSS属性will-change，Chrome/Opera/Firefox都支持该属性&lt;/p&gt;

&lt;div class=&quot;language-css highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nc&quot;&gt;.moving-element&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;will-change&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;或者，对于旧版本或不支持will-change属性的浏览器通过 &lt;code class=&quot;highlighter-rouge&quot;&gt;translateZ(0)&lt;/code&gt; 或者 &lt;code class=&quot;highlighter-rouge&quot;&gt;opacity&lt;/code&gt; &amp;lt; 1：&lt;/p&gt;

&lt;div class=&quot;language-css highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nc&quot;&gt;.moving-element&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;translateZ&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;创建一个新的渲染层并不是免费的，它得消耗额外的内存和管理资源。实际上，在内存资源有限的设备上，由于过多的渲染层来带的开销而对页面渲染性能产生的影响，甚至远远超过了它在性能改善上带来的好处。由于每个渲染层的纹理都需要上传到GPU处理，因此我们还需要考虑CPU和GPU之间的带宽问题、以及有多大内存供GPU处理这些纹理的问题。&lt;/p&gt;

&lt;p&gt;参考资料&lt;/p&gt;

&lt;blockquote&gt;
  &lt;ol&gt;
    &lt;li&gt;&lt;a href=&quot;https://developers.google.cn/web/fundamentals/performance/rendering/simplify-paint-complexity-and-reduce-paint-areas?hl=zh-cn&quot;&gt;简化绘制的复杂度、减小绘制区域&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://developers.google.cn/web/fundamentals/performance/rendering/stick-to-compositor-only-properties-and-manage-layer-count?hl=zh-cn&quot;&gt;优先使用渲染层合并属性、控制层数量&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://www.w3ctrain.com/2015/12/15/smoother-animation/&quot;&gt;前端性能优化之更平滑的动画&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;http://div.io/topic/1348&quot;&gt;CSS3硬件加速也有坑！！！&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;http://www.nvidia.cn/object/what-is-gpu-computing-cn.html&quot;&gt;什么是 GPU 加速计算？&lt;/a&gt;&lt;/li&gt;
  &lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;推荐阅读&lt;/p&gt;

&lt;blockquote&gt;
  &lt;ol&gt;
    &lt;li&gt;&lt;a href=&quot;https://www.w3ctrain.com/2015/11/25/how-to-animate-box-shadow/&quot;&gt;如何让box-shadow动画有更平滑的表现&lt;/a&gt;&lt;/li&gt;
  &lt;/ol&gt;
&lt;/blockquote&gt;</content><author><name></name></author><summary type="html">webkit 简介     首发于2003年的safari浏览器。WebKit的代码源自1998年所开发的KDE的HTML排版引擎KHTML及KDE的JavaScript引擎KJS的代码， 当时webkit仅为khtml与kjs的一个fork版本，将他们重新命名为 WebCore 及 JavaScriptCore。 之后因为各平台需要发展出不同的分支，像chromium，qtwebkit等</summary></entry><entry><title type="html">DOM批量处理与 layout thrashing</title><link href="/webkit/performance/2017/01/10/layout-thrashing.html" rel="alternate" type="text/html" title="DOM批量处理与 layout thrashing" /><published>2017-01-10T02:59:45+00:00</published><updated>2017-01-10T02:59:45+00:00</updated><id>/webkit/performance/2017/01/10/layout-thrashing</id><content type="html" xml:base="/webkit/performance/2017/01/10/layout-thrashing.html">&lt;h2 id=&quot;关于layout-thrashing&quot;&gt;关于layout thrashing&lt;/h2&gt;
&lt;p&gt;    当对dom节点一些布局属性发生改变时，往往会导致浏览器布局的重绘，重绘简单的说就是cpu将整个 &lt;code class=&quot;highlighter-rouge&quot;&gt;render tree &lt;/code&gt;按照像素点计算一遍并显示在浏览器上。 浏览器内核为了尽可能的避免重绘，采取了一种&lt;code class=&quot;highlighter-rouge&quot;&gt;lazy load&lt;/code&gt;的方式，当对dom节点布局属性发生写的操作时浏览器会等待直到当前的操作结束，才会触发布局重绘，但是如果当前运行帧中调用dom布局属性的写入后并重新读取， dom会强制同步更新(&lt;code class=&quot;highlighter-rouge&quot;&gt;forced synchonous layout&lt;/code&gt;)以便dom布局属性的正常读取。这种dom的批量就会导致layout thrashing的产生&lt;/p&gt;

&lt;p&gt;看下面这个例子：&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;iWidth&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;oElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;clientWith&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;oElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;iWidth&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'px'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;iWidth1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;oElement1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;clientWith&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;oElement1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;iWidth1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'px'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;当 &lt;code class=&quot;highlighter-rouge&quot;&gt;oElement.style.width = iWidth + 100 + 'px';&lt;/code&gt;时，浏览器缓存更新并等待当前帧运行结束， 这时又发生了一次dom布局属性的读取，浏览器会触发同步强制更新layout，之后在执行对dom的读取，这种更新如果批量进行在比较现代的浏览器上的体验不是很明显但是在移动端与一些老旧的浏览器上消耗的性能还是很明显的&lt;/p&gt;

&lt;h2 id=&quot;以下列举了会导致layout-thrashing的dom属性&quot;&gt;以下列举了会导致layout thrashing的dom属性&lt;/h2&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;1. clientHeight             11. offsetParent
2. clientLeft               12. offsetTop
3. clientTop                13. offsetWidth
4. clientWidth              14. outText
5. focus()                  15. scrollByLines()
6. getBoundingClientRect()  16. scrollPages()
7. getClientRects()         17. scrollHeight
8. innerText                18. scrollIntoView
9. offsetHeight             19. scrollIntoViewIfNeeded()
10. offsetLeft              20. scrollLeft

21 scrollTop
22 scrollWidth
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id=&quot;解决方案&quot;&gt;解决方案&lt;/h2&gt;

&lt;h3 id=&quot;调整dom执行顺序&quot;&gt;调整dom执行顺序&lt;/h3&gt;
&lt;p&gt;以上例来说，我们只需要改成就可以了&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;iWidth&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;oElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;clientWith&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;iWidth1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;oElement1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;clientWith&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;oElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;iWidth&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'px'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;oElement1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;iWidth1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'px'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;以上方法浏览器会等待js执行结束并批量更新。&lt;br /&gt;
    但是实际业务中，我们为了业务的需要会将代码尽量解耦，如果我们按照这个方案处理的话，我们就需要调整代码执行顺序， 导致代码的混乱不堪。这个时候我们就需要raf(&lt;code class=&quot;highlighter-rouge&quot;&gt;requestAnimationFrame&lt;/code&gt;)来解决这个问题：&lt;/p&gt;

&lt;h3 id=&quot;raf-解决方案&quot;&gt;raf 解决方案&lt;/h3&gt;
&lt;p&gt;    &lt;code class=&quot;highlighter-rouge&quot;&gt;requestAnimationFrame&lt;/code&gt; 是通过将所有的dom操作放到下一帧去处理&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;iWidth&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;oElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;clientWith&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;requestAnimationFrame&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;oElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;iWidth&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'px'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;iWidth1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;oElement1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;clientWith&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;requestAnimationFrame&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;oElement1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;iWidth1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'px'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;如果需要调整dom的执行顺序可以通过 &lt;strong&gt;事件回调&lt;/strong&gt; 的方式去处理。&lt;/p&gt;

&lt;h2 id=&quot;参考资料可能需要翻墙&quot;&gt;参考资料(可能需要翻墙)&lt;/h2&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;https://developers.google.cn/web/fundamentals/performance/rendering/avoid-large-complex-layouts-and-layout-thrashing?hl=zh-cn&quot;&gt;避免大规模、复杂的布局&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
  &lt;p&gt;业界现在比较流行的框架像 &lt;a href=&quot;https://facebook.github.io/react/&quot;&gt;react&lt;/a&gt; 等都对这种dom批量插入做了非常好的处理，专注于dom批量处理的库可以采用 &lt;a href=&quot;https://github.com/wilsonpage/fastdom&quot;&gt;fastdom&lt;/a&gt; 的方式&lt;/p&gt;
&lt;/blockquote&gt;</content><author><name></name></author><summary type="html">关于layout thrashing     当对dom节点一些布局属性发生改变时，往往会导致浏览器布局的重绘，重绘简单的说就是cpu将整个 render tree 按照像素点计算一遍并显示在浏览器上。 浏览器内核为了尽可能的避免重绘，采取了一种lazy load的方式，当对dom节点布局属性发生写的操作时浏览器会等待直到当前的操作结束，才会触发布局重绘，但是如果当前运行帧中调用dom布局属性的写入后并重新读取， dom会强制同步更新(forced synchonous layout)以便dom布局属性的正常读取。这种dom的批量就会导致layout thrashing的产生</summary></entry><entry><title type="html">关于webpage fps及注意事项</title><link href="/webkit/performance/2016/12/10/fps.html" rel="alternate" type="text/html" title="关于webpage fps及注意事项" /><published>2016-12-10T14:25:45+00:00</published><updated>2016-12-10T14:25:45+00:00</updated><id>/webkit/performance/2016/12/10/fps</id><content type="html" xml:base="/webkit/performance/2016/12/10/fps.html">&lt;p&gt;to be continue&lt;/p&gt;

&lt;p&gt;推荐资料&lt;/p&gt;
&lt;blockquote&gt;
  &lt;ol&gt;
    &lt;li&gt;&lt;a href=&quot;https://developers.google.cn/web/fundamentals/performance/rendering/?hl=zh-cn&quot;&gt;渲染性能&lt;/a&gt;&lt;/li&gt;
  &lt;/ol&gt;
&lt;/blockquote&gt;</content><author><name></name></author><summary type="html">to be continue</summary></entry></feed>