{"articleList":[{"content":"<p>[转自：<a href=\"https://www.jianshu.com/p/97b6259f9773\">https://www.jianshu.com/p/97b6259f9773</a>]</p><p><br></p><blockquote><p>React是现在最流行的前端框架之一，它的轻量化，组件化，单向数据流等特性把前端引入了一个新的高度，现在它又引入的Hooks，一个神奇的东东，来看一看。</p></blockquote><p>你还在为该使用无状态组件（Function）还是有状态组件（Class）而烦恼吗？——拥有了hooks，你再也不需要写Class了，你的所有组件都将是Function。</p><p>你还在为搞不清使用哪个生命周期钩子函数而日夜难眠吗？——拥有了Hooks，生命周期钩子函数可以先丢一边了。</p><p>你在还在为组件中的this指向而晕头转向吗？——既然Class都丢掉了，哪里还有this？你的人生第一次不再需要面对this。</p><p><br></p><p>一个最简单的Hooks</p><p>首先让我们看一下一个简单的有状态组件：</p><p></p><pre><code><span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">class</span> <span class=\"token class-name\" style=\"box-sizing: border-box; color: rgb(248, 197, 85);\">Example</span> <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">extends</span> <span class=\"token class-name\" style=\"box-sizing: border-box; color: rgb(248, 197, 85);\">React<span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">.</span>Component</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n  <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">constructor</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token parameter\" style=\"box-sizing: border-box;\">props</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n    <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">super</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span>props<span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n    <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">this</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>state <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n      count<span class=\"token punctuation\" style=\"box-sizing: border-box;\">:</span> <span class=\"token number\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">0</span>\n    <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n  <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span>\n  <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">render</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n   <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">return</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span>\n      <span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&lt;</span>div</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span><span class=\"token plain-text\" style=\"box-sizing: border-box;\">\n        </span><span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&lt;</span>p</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span><span class=\"token plain-text\" style=\"box-sizing: border-box;\">You clicked </span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span><span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">this</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>state<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>count<span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span><span class=\"token plain-text\" style=\"box-sizing: border-box;\"> times</span><span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\"><!--</span-->p</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span><span class=\"token plain-text\" style=\"box-sizing: border-box;\">\n        </span><span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&lt;</span>button</span> <span class=\"token attr-name\" style=\"box-sizing: border-box;\">onClick</span><span class=\"token script language-javascript\" style=\"box-sizing: border-box;\"><span class=\"token script-punctuation punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">=</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">{</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">)</span> <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=&gt;</span> <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">this</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">.</span><span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">setState</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">{</span> count<span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">:</span> <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">this</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">.</span>state<span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">.</span>count <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">+</span> <span class=\"token number\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">1</span> <span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">}</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">}</span></span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span><span class=\"token plain-text\" style=\"box-sizing: border-box;\">\n          Click me\n        </span><span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\"><!--</span-->button</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span><span class=\"token plain-text\" style=\"box-sizing: border-box;\">\n      </span><span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\"><!--</span-->div</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span>\n    <span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n  <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span>\n<span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"box-sizing: border-box; position: absolute; pointer-events: none; top: 0px; left: -3.8em; width: 3em; letter-spacing: -1px; border-right: 1px solid rgb(153, 153, 153); user-select: none;\"></span></span></span></span></code></pre><p><br></p><p>我们再来看一下使用hooks后的版本：</p><p></p><pre><code><span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">import</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span> useState <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span> <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">from</span> <span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">'react'</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n\n<span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">function</span> <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">Example</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n  <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">const</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">[</span>count<span class=\"token punctuation\" style=\"box-sizing: border-box;\">,</span> setCount<span class=\"token punctuation\" style=\"box-sizing: border-box;\">]</span> <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=</span> <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">useState</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token number\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">0</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n  <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">return</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span>\n    <span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&lt;</span>div</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span><span class=\"token plain-text\" style=\"box-sizing: border-box;\">\n      </span><span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&lt;</span>p</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span><span class=\"token plain-text\" style=\"box-sizing: border-box;\">You clicked </span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>count<span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span><span class=\"token plain-text\" style=\"box-sizing: border-box;\"> times</span><span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\"><!--</span-->p</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span><span class=\"token plain-text\" style=\"box-sizing: border-box;\">\n      </span><span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&lt;</span>button</span> <span class=\"token attr-name\" style=\"box-sizing: border-box;\">onClick</span><span class=\"token script language-javascript\" style=\"box-sizing: border-box;\"><span class=\"token script-punctuation punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">=</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">{</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">)</span> <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=&gt;</span> <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">setCount</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">(</span>count <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">+</span> <span class=\"token number\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">1</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">}</span></span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span><span class=\"token plain-text\" style=\"box-sizing: border-box;\">\n        Click me\n      </span><span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\"><!--</span-->button</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span><span class=\"token plain-text\" style=\"box-sizing: border-box;\">\n    </span><span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\"><!--</span-->div</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span>\n  <span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n<span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"box-sizing: border-box; position: absolute; pointer-events: none; top: 0px; left: -3.8em; width: 3em; letter-spacing: -1px; border-right: 1px solid rgb(153, 153, 153); user-select: none;\"></span></span></span></span></code></pre><p>是不是简单多了！可以看到， Example变成了一个函数，但这个函数却有自己的状态（count），同时它还可以更新自己的状态（setCount）。这个函数之所以这么了不得，就是因为它注入了一个hook-- useState，就是这个hook让我们的函数变成了一个有状态的函数。</p><p><br></p><p>除了 useState这个hook外，还有很多别的hook，比如 useEffect提供了类似于 componentDidMount等生命周期钩子的功能， useContext提供了上下文（context）的功能等等。</p><p>Hooks本质上就是一类特殊的函数，它们可以为你的函数型组件（function component）注入一些特殊的功能。咦？这听起来有点像被诟病的Mixins啊？难道是Mixins要在react中死灰复燃了吗？当然不会了，等会我们再来谈两者的区别。总而言之，这些hooks的目标就是让你不再写class，让function一统江湖。</p><p>React为什么要搞一个Hooks？</p><p>想要复用一个有状态的组件太麻烦了！</p><p><br></p><p>我们都知道react都核心思想就是，将一个页面拆成一堆独立的，可复用的组件，并且用自上而下的单向数据流的形式将这些组件串联起来。但假如你在大型的工作项目中用react，你会发现你的项目中实际上很多react组件冗长且难以复用。尤其是那些写成class的组件，它们本身包含了状态（state），所以复用这类组件就变得很麻烦。</p><p>那之前，官方推荐怎么解决这个问题呢？答案是：渲染属性（Render Props）和高阶组件（Higher-Order Components）。我们可以稍微跑下题简单看一下这两种模式。</p><p>渲染属性指的是使用一个值为函数的prop来传递需要动态渲染的nodes或组件。如下面的代码可以看到我们的 DataProvider组件包含了所有跟状态相关的代码，而 Cat组件则可以是一个单纯的展示型组件，这样一来 DataProvider就可以单独复用了。</p><p></p><pre><code><span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">import</span> Cat <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">from</span> <span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">'components/cat'</span>\n\n<span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">class</span> <span class=\"token class-name\" style=\"box-sizing: border-box; color: rgb(248, 197, 85);\">DataProvider</span> <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">extends</span> <span class=\"token class-name\" style=\"box-sizing: border-box; color: rgb(248, 197, 85);\">React<span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">.</span>Component</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n  <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">constructor</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token parameter\" style=\"box-sizing: border-box;\">props</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n    <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">super</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span>props<span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n    <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">this</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>state <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span> target<span class=\"token punctuation\" style=\"box-sizing: border-box;\">:</span> <span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">'Zac'</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n  <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span>\n\n  <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">render</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n    <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">return</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span>\n      <span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&lt;</span>div</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span><span class=\"token plain-text\" style=\"box-sizing: border-box;\">\n        </span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span><span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">this</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>props<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span><span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">render</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">this</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>state<span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span><span class=\"token plain-text\" style=\"box-sizing: border-box;\">\n      </span><span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\"><!--</span-->div</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span>\n    <span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span>\n  <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span>\n<span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span>\n\n<span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&lt;</span><span class=\"token class-name\" style=\"box-sizing: border-box; color: rgb(248, 197, 85);\">DataProvider</span></span> <span class=\"token attr-name\" style=\"box-sizing: border-box;\">render</span><span class=\"token script language-javascript\" style=\"box-sizing: border-box;\"><span class=\"token script-punctuation punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">=</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">{</span><span class=\"token parameter\" style=\"box-sizing: border-box;\">data</span> <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=&gt;</span> <span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">(</span>\n  <span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&lt;</span><span class=\"token class-name\" style=\"box-sizing: border-box; color: rgb(248, 197, 85);\">Cat</span></span> <span class=\"token attr-name\" style=\"box-sizing: border-box;\">target</span><span class=\"token script language-javascript\" style=\"box-sizing: border-box;\"><span class=\"token script-punctuation punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">=</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">{</span>data<span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">.</span>target<span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">}</span></span> <span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">/&gt;</span></span>\n<span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">}</span></span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">/&gt;</span></span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"box-sizing: border-box; position: absolute; pointer-events: none; top: 0px; left: -3.8em; width: 3em; letter-spacing: -1px; border-right: 1px solid rgb(153, 153, 153); user-select: none;\"></span></span></code></pre><p><br></p><p>虽然这个模式叫Render Props，但不是说非用一个叫render的props不可，习惯上大家更常写成下面这种：</p><p></p><pre><code>...\n\n<span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&lt;</span>DataProvider</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span>\n  {data =&gt; (\n    <span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&lt;</span>Cat</span> <span class=\"token attr-name\" style=\"box-sizing: border-box;\">target</span><span class=\"token attr-value\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">=</span>{data.target}</span> <span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">/&gt;</span></span>\n  )}\n<span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\"><!--</span-->DataProvider</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"box-sizing: border-box; position: absolute; pointer-events: none; top: 0px; left: -3.8em; width: 3em; letter-spacing: -1px; border-right: 1px solid rgb(153, 153, 153); user-select: none;\"></span></span></code></pre><p><br></p><p>高阶组件这个概念就更好理解了，说白了就是一个函数接受一个组件作为参数，经过一系列加工后，最后返回一个新的组件。看下面的代码示例，&nbsp;withUser函数就是一个高阶组件，它返回了一个新的组件，这个组件具有了它提供的获取用户信息的功能。</p><p></p><pre><code><span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">const</span> <span class=\"token function-variable function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">withUser</span> <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=</span> <span class=\"token parameter\" style=\"box-sizing: border-box;\">WrappedComponent</span> <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=&gt;</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n  <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">const</span> user <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=</span> sessionStorage<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span><span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">getItem</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">\"user\"</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n  <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">return</span> <span class=\"token parameter\" style=\"box-sizing: border-box;\">props</span> <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=&gt;</span> <span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&lt;</span><span class=\"token class-name\" style=\"box-sizing: border-box; color: rgb(248, 197, 85);\">WrappedComponent</span></span> <span class=\"token attr-name\" style=\"box-sizing: border-box;\">user</span><span class=\"token script language-javascript\" style=\"box-sizing: border-box;\"><span class=\"token script-punctuation punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">=</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">{</span>user<span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">}</span></span> <span class=\"token spread\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">{</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">...</span><span class=\"token attr-value\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">props</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">}</span></span> <span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">/&gt;</span></span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n<span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n\n<span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">const</span> <span class=\"token function-variable function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">UserPage</span> <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=</span> <span class=\"token parameter\" style=\"box-sizing: border-box;\">props</span> <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=&gt;</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span>\n  <span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&lt;</span>div</span> <span class=\"token attr-name\" style=\"box-sizing: border-box;\">class</span><span class=\"token attr-value\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">=</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">\"</span>user-container<span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">\"</span></span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span><span class=\"token plain-text\" style=\"box-sizing: border-box;\">\n    </span><span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&lt;</span>p</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span><span class=\"token plain-text\" style=\"box-sizing: border-box;\">My name is </span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>props<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>user<span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span><span class=\"token plain-text\" style=\"box-sizing: border-box;\">!</span><span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\"><!--</span-->p</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span><span class=\"token plain-text\" style=\"box-sizing: border-box;\">\n  </span><span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\"><!--</span-->div</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span>\n<span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n\n<span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">export</span> <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">default</span> <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">withUser</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span>UserPage<span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"box-sizing: border-box; position: absolute; pointer-events: none; top: 0px; left: -3.8em; width: 3em; letter-spacing: -1px; border-right: 1px solid rgb(153, 153, 153); user-select: none;\"></span></span></span></code></pre><p>以上这两种模式看上去都挺不错的，很多库也运用了这种模式，比如我们常用的React Router。但我们仔细看这两种模式，会发现它们会增加我们代码的层级关系。最直观的体现，打开devtool看看你的组件层级嵌套是不是很夸张吧。这时候再回过头看我们上一节给出的hooks例子，是不是简洁多了，没有多余的层级嵌套。把各种想要的功能写成一个一个可复用的自定义hook，当你的组件想用什么功能时，直接在组件里调用这个hook即可。</p><p><br></p><p>生命周期钩子函数里的逻辑太乱了吧！</p><p>我们通常希望一个函数只做一件事情，但我们的生命周期钩子函数里通常同时做了很多事情。比如我们需要在&nbsp;componentDidMount中发起ajax请求获取数据，绑定一些事件监听等等。同时，有时候我们还需要在&nbsp;componentDidUpdate做一遍同样的事情。当项目变复杂后，这一块的代码也变得不那么直观。</p><p><br></p><p>classes真的太让人困惑了！</p><p>我们用class来创建react组件时，还有一件很麻烦的事情，就是this的指向问题。为了保证this的指向正确，我们要经常写这样的代码：&nbsp;this.handleClick=this.handleClick.bind(this)，或者是这样的代码：&nbsp;this.handleClick(e)}&gt;。一旦我们不小心忘了绑定this，各种bug就随之而来，很麻烦。</p><p>还有一件让我很苦恼的事情。我在之前的react系列文章当中曾经说过，尽可能把你的组件写成无状态组件的形式，因为它们更方便复用，可独立测试。然而很多时候，我们用function写了一个简洁完美的无状态组件，后来因为需求变动这个组件必须得有自己的state，我们又得很麻烦的把function改成class。</p><p>在这样的背景下，Hooks便横空出世了！</p><p><br></p><p>什么是State Hooks？</p><p>回到一开始我们用的例子，我们分解来看到底state hooks做了什么：</p><p></p><pre><code><span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">import</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span> useState <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span> <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">from</span> <span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">'react'</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n\n<span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">function</span> <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">Example</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n  <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">const</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">[</span>count<span class=\"token punctuation\" style=\"box-sizing: border-box;\">,</span> setCount<span class=\"token punctuation\" style=\"box-sizing: border-box;\">]</span> <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=</span> <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">useState</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token number\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">0</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n  <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">return</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span>\n    <span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&lt;</span>div</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span><span class=\"token plain-text\" style=\"box-sizing: border-box;\">\n      </span><span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&lt;</span>p</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span><span class=\"token plain-text\" style=\"box-sizing: border-box;\">You clicked </span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>count<span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span><span class=\"token plain-text\" style=\"box-sizing: border-box;\"> times</span><span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\"><!--</span-->p</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span><span class=\"token plain-text\" style=\"box-sizing: border-box;\">\n      </span><span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&lt;</span>button</span> <span class=\"token attr-name\" style=\"box-sizing: border-box;\">onClick</span><span class=\"token script language-javascript\" style=\"box-sizing: border-box;\"><span class=\"token script-punctuation punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">=</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">{</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">)</span> <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=&gt;</span> <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">setCount</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">(</span>count <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">+</span> <span class=\"token number\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">1</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">}</span></span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span><span class=\"token plain-text\" style=\"box-sizing: border-box;\">\n        Click me\n      </span><span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\"><!--</span-->button</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span><span class=\"token plain-text\" style=\"box-sizing: border-box;\">\n    </span><span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\"><!--</span-->div</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span>\n  <span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n<span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"box-sizing: border-box; position: absolute; pointer-events: none; top: 0px; left: -3.8em; width: 3em; letter-spacing: -1px; border-right: 1px solid rgb(153, 153, 153); user-select: none;\"></span></span></span></span></code></pre><p><br></p><p>声明一个状态变量</p><p></p><pre><code><span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">import</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span> useState <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span> <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">from</span> <span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">'react'</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n\n<span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">function</span> <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">Example</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n  <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">const</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">[</span>count<span class=\"token punctuation\" style=\"box-sizing: border-box;\">,</span> setCount<span class=\"token punctuation\" style=\"box-sizing: border-box;\">]</span> <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=</span> <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">useState</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token number\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">0</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n<span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"box-sizing: border-box; position: absolute; pointer-events: none; top: 0px; left: -3.8em; width: 3em; letter-spacing: -1px; border-right: 1px solid rgb(153, 153, 153); user-select: none;\"></span></code></pre><p>useState是react自带的一个hook函数，它的作用就是用来声明状态变量。 useState这个函数接收的参数是我们的状态初始值（initial state），它返回了一个数组，这个数组的第 [0]项是当前当前的状态值，第 [1]项是可以改变状态值的方法函数。</p><p>所以我们做的事情其实就是，声明了一个状态变量count，把它的初始值设为0，同时提供了一个可以更改count的函数setCount。</p><p>如果不用数组解构的话，可以写成下面这样。实际上数组解构是一件开销很大的事情，用下面这种写法，或者改用对象解构，性能会有很大的提升。具体可以去这篇文章的分析：Array destructuring for multi-value returns (in light of React hooks)，这里不详细展开，我们就按照官方推荐使用数组解构就好。</p><p></p><pre><code><span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">let</span> _useState <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=</span> <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">useState</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token number\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">0</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n<span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">let</span> <span class=\"token builtin\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">count</span> <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=</span> _useState<span class=\"token punctuation\" style=\"box-sizing: border-box;\">[</span><span class=\"token number\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">0</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">]</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n<span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">let</span> setCount <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=</span> _useState<span class=\"token punctuation\" style=\"box-sizing: border-box;\">[</span><span class=\"token number\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">1</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">]</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"box-sizing: border-box; position: absolute; pointer-events: none; top: 0px; left: -3.8em; width: 3em; letter-spacing: -1px; border-right: 1px solid rgb(153, 153, 153); user-select: none;\"></span></code></pre><p><br></p><p>读取状态值</p><p></p><pre><code><span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&lt;</span>p</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span>You clicked {count} times<span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\"><!--</span-->p</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"box-sizing: border-box; position: absolute; pointer-events: none; top: 0px; left: -3.8em; width: 3em; letter-spacing: -1px; border-right: 1px solid rgb(153, 153, 153); user-select: none;\"></span></span></code></pre><p>是不是超简单？因为我们的状态count就是一个单纯的变量而已，我们再也不需要写成&nbsp;{this.state.count}这样了。</p><p><br></p><p>更新状态</p><p></p><pre><code><code></code><button onclick=\"{()\" ==\"\"><code> setCount(count + 1)}&gt;\n    Click me\n<span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\"><!--</span-->button</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"box-sizing: border-box; position: absolute; pointer-events: none; top: 0px; left: -3.8em; width: 3em; letter-spacing: -1px; border-right: 1px solid rgb(153, 153, 153); user-select: none;\"></span></span></code></button></code></pre><p>当用户点击按钮时，我们调用setCount函数，这个函数接收的参数是修改过的新状态值。接下来的事情就交给react了，react将会重新渲染我们的Example组件，并且使用的是更新后的新的状态，即count=1。这里我们要停下来思考一下，Example本质上也是一个普通的函数，为什么它可以记住之前的状态？</p><p><br></p><p>一个至关重要的问题</p><p>这里我们就发现了问题，通常来说我们在一个函数中声明的变量，当函数运行完成后，这个变量也就销毁了（这里我们先不考虑闭包等情况），比如考虑下面的例子：</p><p></p><pre><code>function <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">add</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span>n<span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n    <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">const</span> result <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=</span> <span class=\"token number\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">0</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n    <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">return</span> result <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">+</span> <span class=\"token number\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">1</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n<span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span>\n\n<span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">add</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token number\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">1</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span> <span class=\"token comment\" style=\"box-sizing: border-box; color: rgb(153, 153, 153);\">//1</span>\n<span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">add</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token number\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">1</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span> <span class=\"token comment\" style=\"box-sizing: border-box; color: rgb(153, 153, 153);\">//1</span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"box-sizing: border-box; position: absolute; pointer-events: none; top: 0px; left: -3.8em; width: 3em; letter-spacing: -1px; border-right: 1px solid rgb(153, 153, 153); user-select: none;\"></span></code></pre><p>不管我们反复调用add函数多少次，结果都是1。因为每一次我们调用add时，result变量都是从初始值0开始的。那为什么上面的Example函数每次执行的时候，都是拿的上一次执行完的状态值作为初始值？答案是：是react帮我们记住的。至于react是用什么机制记住的，我们可以再思考一下。</p><p>假如一个组件有多个状态值怎么办？</p><p>首先，useState是可以多次调用的，所以我们完全可以这样写：</p><p></p><pre><code><span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">function</span> <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">ExampleWithManyStates</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n  <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">const</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">[</span>age<span class=\"token punctuation\" style=\"box-sizing: border-box;\">,</span> setAge<span class=\"token punctuation\" style=\"box-sizing: border-box;\">]</span> <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=</span> <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">useState</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token number\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">42</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n  <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">const</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">[</span>fruit<span class=\"token punctuation\" style=\"box-sizing: border-box;\">,</span> setFruit<span class=\"token punctuation\" style=\"box-sizing: border-box;\">]</span> <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=</span> <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">useState</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">'banana'</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n  <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">const</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">[</span>todos<span class=\"token punctuation\" style=\"box-sizing: border-box;\">,</span> setTodos<span class=\"token punctuation\" style=\"box-sizing: border-box;\">]</span> <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=</span> <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">useState</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">[</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span> text<span class=\"token punctuation\" style=\"box-sizing: border-box;\">:</span> <span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">'Learn Hooks'</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">]</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n<span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"box-sizing: border-box; position: absolute; pointer-events: none; top: 0px; left: -3.8em; width: 3em; letter-spacing: -1px; border-right: 1px solid rgb(153, 153, 153); user-select: none;\"></span></code></pre><p>其次，useState接收的初始值没有规定一定要是string/number/boolean这种简单数据类型，它完全可以接收对象或者数组作为参数。唯一需要注意的点是，之前我们的 this.setState做的是合并状态后返回一个新状态，而 useState是直接替换老状态后返回新状态。最后，react也给我们提供了一个useReducer的hook，如果你更喜欢redux式的状态管理方案的话。</p><p>从ExampleWithManyStates函数我们可以看到，useState无论调用多少次，相互之间是独立的。这一点至关重要。为什么这么说呢？</p><p>其实我们看hook的“形态”，有点类似之前被官方否定掉的Mixins这种方案，都是提供一种“插拔式的功能注入”的能力。而mixins之所以被否定，是因为Mixins机制是让多个Mixins共享一个对象的数据空间，这样就很难确保不同Mixins依赖的状态不发生冲突。</p><p>而现在我们的hook，一方面它是直接用在function当中，而不是class；另一方面每一个hook都是相互独立的，不同组件调用同一个hook也能保证各自状态的独立性。这就是两者的本质区别了。</p><p>react是怎么保证多个useState的相互独立的？</p><p>还是看上面给出的ExampleWithManyStates例子，我们调用了三次useState，每次我们传的参数只是一个值（如42，‘banana’），我们根本没有告诉react这些值对应的key是哪个，那react是怎么保证这三个useState找到它对应的state呢？</p><p><br></p><p>答案是，react是根据useState出现的顺序来定的。我们具体来看一下：</p><p></p><pre><code>  <span class=\"token comment\" style=\"box-sizing: border-box; color: rgb(153, 153, 153);\">//第一次渲染</span>\n  <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">useState</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token number\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">42</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>  <span class=\"token comment\" style=\"box-sizing: border-box; color: rgb(153, 153, 153);\">//将age初始化为42</span>\n  <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">useState</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">'banana'</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>  <span class=\"token comment\" style=\"box-sizing: border-box; color: rgb(153, 153, 153);\">//将fruit初始化为banana</span>\n  <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">useState</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">[</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span> text<span class=\"token punctuation\" style=\"box-sizing: border-box;\">:</span> <span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">'Learn Hooks'</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">]</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span> <span class=\"token comment\" style=\"box-sizing: border-box; color: rgb(153, 153, 153);\">//...</span>\n  <span class=\"token comment\" style=\"box-sizing: border-box; color: rgb(153, 153, 153);\">//第二次渲染</span>\n  <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">useState</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token number\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">42</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>  <span class=\"token comment\" style=\"box-sizing: border-box; color: rgb(153, 153, 153);\">//读取状态变量age的值（这时候传的参数42直接被忽略）</span>\n  <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">useState</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">'banana'</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>  <span class=\"token comment\" style=\"box-sizing: border-box; color: rgb(153, 153, 153);\">//读取状态变量fruit的值（这时候传的参数banana直接被忽略）</span>\n  <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">useState</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">[</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span> text<span class=\"token punctuation\" style=\"box-sizing: border-box;\">:</span> <span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">'Learn Hooks'</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">]</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span> <span class=\"token comment\" style=\"box-sizing: border-box; color: rgb(153, 153, 153);\">//...</span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"box-sizing: border-box; position: absolute; pointer-events: none; top: 0px; left: -3.8em; width: 3em; letter-spacing: -1px; border-right: 1px solid rgb(153, 153, 153); user-select: none;\"></span></code></pre><p>假如我们改一下代码：</p><p></p><pre><code><span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">let</span> showFruit <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=</span> <span class=\"token boolean\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">true</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n<span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">function</span> <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">ExampleWithManyStates</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n  <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">const</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">[</span>age<span class=\"token punctuation\" style=\"box-sizing: border-box;\">,</span> setAge<span class=\"token punctuation\" style=\"box-sizing: border-box;\">]</span> <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=</span> <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">useState</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token number\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">42</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n  <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">if</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span>showFruit<span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n    <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">const</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">[</span>fruit<span class=\"token punctuation\" style=\"box-sizing: border-box;\">,</span> setFruit<span class=\"token punctuation\" style=\"box-sizing: border-box;\">]</span> <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=</span> <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">useState</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">'banana'</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n    showFruit <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=</span> <span class=\"token boolean\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">false</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n  <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span>\n  <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">const</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">[</span>todos<span class=\"token punctuation\" style=\"box-sizing: border-box;\">,</span> setTodos<span class=\"token punctuation\" style=\"box-sizing: border-box;\">]</span> <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=</span> <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">useState</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">[</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span> text<span class=\"token punctuation\" style=\"box-sizing: border-box;\">:</span> <span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">'Learn Hooks'</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">]</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n<span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"box-sizing: border-box; position: absolute; pointer-events: none; top: 0px; left: -3.8em; width: 3em; letter-spacing: -1px; border-right: 1px solid rgb(153, 153, 153); user-select: none;\"></span></code></pre><p>这样一来，</p><p></p><pre><code>  <span class=\"token comment\" style=\"box-sizing: border-box; color: rgb(153, 153, 153);\">//第一次渲染</span>\n  <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">useState</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token number\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">42</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>  <span class=\"token comment\" style=\"box-sizing: border-box; color: rgb(153, 153, 153);\">//将age初始化为42</span>\n  <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">useState</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">'banana'</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>  <span class=\"token comment\" style=\"box-sizing: border-box; color: rgb(153, 153, 153);\">//将fruit初始化为banana</span>\n  <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">useState</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">[</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span> text<span class=\"token punctuation\" style=\"box-sizing: border-box;\">:</span> <span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">'Learn Hooks'</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">]</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span> <span class=\"token comment\" style=\"box-sizing: border-box; color: rgb(153, 153, 153);\">//...</span>\n\n  <span class=\"token comment\" style=\"box-sizing: border-box; color: rgb(153, 153, 153);\">//第二次渲染</span>\n  <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">useState</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token number\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">42</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>  <span class=\"token comment\" style=\"box-sizing: border-box; color: rgb(153, 153, 153);\">//读取状态变量age的值（这时候传的参数42直接被忽略）</span>\n  <span class=\"token comment\" style=\"box-sizing: border-box; color: rgb(153, 153, 153);\">// useState('banana');  </span>\n  <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">useState</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">[</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span> text<span class=\"token punctuation\" style=\"box-sizing: border-box;\">:</span> <span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">'Learn Hooks'</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">]</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span> <span class=\"token comment\" style=\"box-sizing: border-box; color: rgb(153, 153, 153);\">//读取到的却是状态变量fruit的值，导致报错</span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"box-sizing: border-box; position: absolute; pointer-events: none; top: 0px; left: -3.8em; width: 3em; letter-spacing: -1px; border-right: 1px solid rgb(153, 153, 153); user-select: none;\"></span></code></pre><p>鉴于此，react规定我们必须把hooks写在函数的最外层，不能写在ifelse等条件语句当中，来确保hooks的执行顺序一致。</p><p>什么是Effect Hooks?</p><p>我们在上一节的例子中增加一个新功能：</p><p></p><pre><code><span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">import</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span> useState<span class=\"token punctuation\" style=\"box-sizing: border-box;\">,</span> useEffect <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span> <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">from</span> <span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">'react'</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n\n<span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">function</span> <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">Example</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n  <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">const</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">[</span>count<span class=\"token punctuation\" style=\"box-sizing: border-box;\">,</span> setCount<span class=\"token punctuation\" style=\"box-sizing: border-box;\">]</span> <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=</span> <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">useState</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token number\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">0</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n  <span class=\"token comment\" style=\"box-sizing: border-box; color: rgb(153, 153, 153);\">// 类似于componentDidMount 和 componentDidUpdate:</span>\n  <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">useEffect</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span> <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=&gt;</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n    <span class=\"token comment\" style=\"box-sizing: border-box; color: rgb(153, 153, 153);\">// 更新文档的标题</span>\n    document<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>title <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=</span> <span class=\"token template-string\" style=\"box-sizing: border-box;\"><span class=\"token template-punctuation string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">`</span><span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">You clicked </span><span class=\"token interpolation\" style=\"box-sizing: border-box;\"><span class=\"token interpolation-punctuation punctuation\" style=\"box-sizing: border-box;\">${</span>count<span class=\"token interpolation-punctuation punctuation\" style=\"box-sizing: border-box;\">}</span></span><span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\"> times</span><span class=\"token template-punctuation string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">`</span></span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n  <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n\n  <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">return</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span>\n    <span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&lt;</span>div</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span><span class=\"token plain-text\" style=\"box-sizing: border-box;\">\n      </span><span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&lt;</span>p</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span><span class=\"token plain-text\" style=\"box-sizing: border-box;\">You clicked </span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>count<span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span><span class=\"token plain-text\" style=\"box-sizing: border-box;\"> times</span><span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\"><!--</span-->p</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span><span class=\"token plain-text\" style=\"box-sizing: border-box;\">\n      </span><span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&lt;</span>button</span> <span class=\"token attr-name\" style=\"box-sizing: border-box;\">onClick</span><span class=\"token script language-javascript\" style=\"box-sizing: border-box;\"><span class=\"token script-punctuation punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">=</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">{</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">)</span> <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=&gt;</span> <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">setCount</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">(</span>count <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">+</span> <span class=\"token number\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">1</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">}</span></span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span><span class=\"token plain-text\" style=\"box-sizing: border-box;\">\n        Click me\n      </span><span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\"><!--</span-->button</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span><span class=\"token plain-text\" style=\"box-sizing: border-box;\">\n    </span><span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\"><!--</span-->div</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span>\n  <span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n<span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"box-sizing: border-box; position: absolute; pointer-events: none; top: 0px; left: -3.8em; width: 3em; letter-spacing: -1px; border-right: 1px solid rgb(153, 153, 153); user-select: none;\"></span></span></span></span></code></pre><p>我们对比着看一下，如果没有hooks，我们会怎么写？</p><p></p><pre><code><span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">class</span> <span class=\"token class-name\" style=\"box-sizing: border-box; color: rgb(248, 197, 85);\">Example</span> <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">extends</span> <span class=\"token class-name\" style=\"box-sizing: border-box; color: rgb(248, 197, 85);\">React<span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">.</span>Component</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n  <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">constructor</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token parameter\" style=\"box-sizing: border-box;\">props</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n    <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">super</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span>props<span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n    <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">this</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>state <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n      count<span class=\"token punctuation\" style=\"box-sizing: border-box;\">:</span> <span class=\"token number\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">0</span>\n    <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n  <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span>\n\n  <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">componentDidMount</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n    document<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>title <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=</span> <span class=\"token template-string\" style=\"box-sizing: border-box;\"><span class=\"token template-punctuation string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">`</span><span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">You clicked </span><span class=\"token interpolation\" style=\"box-sizing: border-box;\"><span class=\"token interpolation-punctuation punctuation\" style=\"box-sizing: border-box;\">${</span><span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">this</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>state<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>count<span class=\"token interpolation-punctuation punctuation\" style=\"box-sizing: border-box;\">}</span></span><span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\"> times</span><span class=\"token template-punctuation string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">`</span></span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n  <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span>\n\n  <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">componentDidUpdate</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n    document<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>title <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=</span> <span class=\"token template-string\" style=\"box-sizing: border-box;\"><span class=\"token template-punctuation string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">`</span><span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">You clicked </span><span class=\"token interpolation\" style=\"box-sizing: border-box;\"><span class=\"token interpolation-punctuation punctuation\" style=\"box-sizing: border-box;\">${</span><span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">this</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>state<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>count<span class=\"token interpolation-punctuation punctuation\" style=\"box-sizing: border-box;\">}</span></span><span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\"> times</span><span class=\"token template-punctuation string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">`</span></span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n  <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span>\n\n  <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">render</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n    <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">return</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span>\n      <span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&lt;</span>div</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span><span class=\"token plain-text\" style=\"box-sizing: border-box;\">\n        </span><span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&lt;</span>p</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span><span class=\"token plain-text\" style=\"box-sizing: border-box;\">You clicked </span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span><span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">this</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>state<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>count<span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span><span class=\"token plain-text\" style=\"box-sizing: border-box;\"> times</span><span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\"><!--</span-->p</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span><span class=\"token plain-text\" style=\"box-sizing: border-box;\">\n        </span><span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&lt;</span>button</span> <span class=\"token attr-name\" style=\"box-sizing: border-box;\">onClick</span><span class=\"token script language-javascript\" style=\"box-sizing: border-box;\"><span class=\"token script-punctuation punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">=</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">{</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">)</span> <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=&gt;</span> <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">this</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">.</span><span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">setState</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">{</span> count<span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">:</span> <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">this</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">.</span>state<span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">.</span>count <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">+</span> <span class=\"token number\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">1</span> <span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">}</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">}</span></span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span><span class=\"token plain-text\" style=\"box-sizing: border-box;\">\n          Click me\n        </span><span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\"><!--</span-->button</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span><span class=\"token plain-text\" style=\"box-sizing: border-box;\">\n      </span><span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\"><!--</span-->div</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span>\n    <span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n  <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span>\n<span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"box-sizing: border-box; position: absolute; pointer-events: none; top: 0px; left: -3.8em; width: 3em; letter-spacing: -1px; border-right: 1px solid rgb(153, 153, 153); user-select: none;\"></span></span></span></span></code></pre><p>我们写的有状态组件，通常会产生很多的副作用（side effect），比如发起ajax请求获取数据，添加一些监听的注册和取消注册，手动修改dom等等。我们之前都把这些副作用的函数写在生命周期函数钩子里，比如componentDidMount，componentDidUpdate和componentWillUnmount。而现在的useEffect就相当与这些声明周期函数钩子的集合体。它以一抵三。</p><p>同时，由于前文所说hooks可以反复多次使用，相互独立。所以我们合理的做法是，给每一个副作用一个单独的useEffect钩子。这样一来，这些副作用不再一股脑堆在生命周期钩子里，代码变得更加清晰。</p><p>useEffect做了什么？</p><p>我们再梳理一遍下面代码的逻辑：</p><p></p><pre><code><span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">function</span> <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">Example</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n  <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">const</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">[</span>count<span class=\"token punctuation\" style=\"box-sizing: border-box;\">,</span> setCount<span class=\"token punctuation\" style=\"box-sizing: border-box;\">]</span> <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=</span> <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">useState</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token number\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">0</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n\n  <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">useEffect</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span> <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=&gt;</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n    document<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>title <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=</span> <span class=\"token template-string\" style=\"box-sizing: border-box;\"><span class=\"token template-punctuation string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">`</span><span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">You clicked </span><span class=\"token interpolation\" style=\"box-sizing: border-box;\"><span class=\"token interpolation-punctuation punctuation\" style=\"box-sizing: border-box;\">${</span>count<span class=\"token interpolation-punctuation punctuation\" style=\"box-sizing: border-box;\">}</span></span><span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\"> times</span><span class=\"token template-punctuation string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">`</span></span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n  <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n<span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"box-sizing: border-box; position: absolute; pointer-events: none; top: 0px; left: -3.8em; width: 3em; letter-spacing: -1px; border-right: 1px solid rgb(153, 153, 153); user-select: none;\"></span></code></pre><p>首先，我们声明了一个状态变量 count，将它的初始值设为0。然后我们告诉react，我们的这个组件有一个副作用。我们给 useEffecthook传了一个匿名函数，这个匿名函数就是我们的副作用。在这个例子里，我们的副作用是调用browser API来修改文档标题。当react要渲染我们的组件时，它会先记住我们用到的副作用。等react更新了DOM之后，它再依次执行我们定义的副作用函数。</p><p>这里要注意几点：</p><p>第一，react首次渲染和之后的每次渲染都会调用一遍传给useEffect的函数。而之前我们要用两个声明周期函数来分别表示首次渲染（componentDidMount），和之后的更新导致的重新渲染（componentDidUpdate）。</p><p>第二，useEffect中定义的副作用函数的执行不会阻碍浏览器更新视图，也就是说这些函数是异步执行的，而之前的componentDidMount或componentDidUpdate中的代码则是同步执行的。这种安排对大多数副作用说都是合理的，但有的情况除外，比如我们有时候需要先根据DOM计算出某个元素的尺寸再重新渲染，这时候我们希望这次重新渲染是同步发生的，也就是说它会在浏览器真的去绘制这个页面前发生。</p><p>useEffect怎么解绑一些副作用</p><p>这种场景很常见，当我们在componentDidMount里添加了一个注册，我们得马上在componentWillUnmount中，也就是组件被注销之前清除掉我们添加的注册，否则内存泄漏的问题就出现了。</p><p>怎么清除呢？让我们传给useEffect的副作用函数返回一个新的函数即可。这个新的函数将会在组件下一次重新渲染之后执行。这种模式在一些pubsub模式的实现中很常见。看下面的例子：</p><p></p><pre><code><span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">import</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span> useState<span class=\"token punctuation\" style=\"box-sizing: border-box;\">,</span> useEffect <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span> <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">from</span> <span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">'react'</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n\n<span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">function</span> <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">FriendStatus</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token parameter\" style=\"box-sizing: border-box;\">props</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n  <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">const</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">[</span>isOnline<span class=\"token punctuation\" style=\"box-sizing: border-box;\">,</span> setIsOnline<span class=\"token punctuation\" style=\"box-sizing: border-box;\">]</span> <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=</span> <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">useState</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">null</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n\n  <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">function</span> <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">handleStatusChange</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token parameter\" style=\"box-sizing: border-box;\">status</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n    <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">setIsOnline</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span>status<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>isOnline<span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n  <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span>\n\n  <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">useEffect</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span> <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=&gt;</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n    ChatAPI<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span><span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">subscribeToFriendStatus</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span>props<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>friend<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>id<span class=\"token punctuation\" style=\"box-sizing: border-box;\">,</span> handleStatusChange<span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n    <span class=\"token comment\" style=\"box-sizing: border-box; color: rgb(153, 153, 153);\">// 一定注意下这个顺序：告诉react在下次重新渲染组件之后，同时是下次调用ChatAPI.subscribeToFriendStatus之前执行cleanup</span>\n    <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">return</span> <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">function</span> <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">cleanup</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n      ChatAPI<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span><span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">unsubscribeFromFriendStatus</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span>props<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>friend<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>id<span class=\"token punctuation\" style=\"box-sizing: border-box;\">,</span> handleStatusChange<span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n    <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n  <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n\n  <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">if</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span>isOnline <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">===</span> <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">null</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n    <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">return</span> <span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">'Loading...'</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n  <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span>\n  <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">return</span> isOnline <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">?</span> <span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">'Online'</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">:</span> <span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">'Offline'</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n<span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"box-sizing: border-box; position: absolute; pointer-events: none; top: 0px; left: -3.8em; width: 3em; letter-spacing: -1px; border-right: 1px solid rgb(153, 153, 153); user-select: none;\"></span></code></pre><p>这里有一个点需要重视！这种解绑的模式跟componentWillUnmount不一样。componentWillUnmount只会在组件被销毁前执行一次而已，而useEffect里的函数，每次组件渲染后都会执行一遍，包括副作用函数返回的这个清理函数也会重新执行一遍。所以我们一起来看一下下面这个问题。</p><p>为什么要让副作用函数每次组件更新都执行一遍？</p><p>我们先看以前的模式：</p><p></p><pre><code>  <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">componentDidMount</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n    ChatAPI<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span><span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">subscribeToFriendStatus</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span>\n      <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">this</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>props<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>friend<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>id<span class=\"token punctuation\" style=\"box-sizing: border-box;\">,</span>\n      <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">this</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>handleStatusChange\n    <span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n  <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span>\n\n  <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">componentWillUnmount</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n    ChatAPI<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span><span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">unsubscribeFromFriendStatus</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span>\n      <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">this</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>props<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>friend<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>id<span class=\"token punctuation\" style=\"box-sizing: border-box;\">,</span>\n      <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">this</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>handleStatusChange\n    <span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n  <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"box-sizing: border-box; position: absolute; pointer-events: none; top: 0px; left: -3.8em; width: 3em; letter-spacing: -1px; border-right: 1px solid rgb(153, 153, 153); user-select: none;\"></span></code></pre><p>很清楚，我们在componentDidMount注册，再在componentWillUnmount清除注册。但假如这时候 props.friend.id变了怎么办？我们不得不再添加一个componentDidUpdate来处理这种情况：</p><p></p><pre><code><span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">..</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>\n\n  <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">componentDidUpdate</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span>prevProps<span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n    <span class=\"token comment\" style=\"box-sizing: border-box; color: rgb(153, 153, 153);\">// 先把上一个friend.id解绑</span>\n    ChatAPI<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span><span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">unsubscribeFromFriendStatus</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span>\n      prevProps<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>friend<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>id<span class=\"token punctuation\" style=\"box-sizing: border-box;\">,</span>\n      <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">this</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>handleStatusChange\n    <span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n\n    <span class=\"token comment\" style=\"box-sizing: border-box; color: rgb(153, 153, 153);\">// 再重新注册新但friend.id</span>\n    ChatAPI<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span><span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">subscribeToFriendStatus</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span>\n      <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">this</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>props<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>friend<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>id<span class=\"token punctuation\" style=\"box-sizing: border-box;\">,</span>\n      <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">this</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>handleStatusChange\n    <span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n  <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span>\n<span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">..</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"box-sizing: border-box; position: absolute; pointer-events: none; top: 0px; left: -3.8em; width: 3em; letter-spacing: -1px; border-right: 1px solid rgb(153, 153, 153); user-select: none;\"></span></code></pre><p>看到了吗？很繁琐，而我们但useEffect则没这个问题，因为它在每次组件更新后都会重新执行一遍。所以代码的执行顺序是这样的：</p><ol><li>页面首次渲染</li><li>替friend.id=1的朋友注册</li><li>突然friend.id变成了2</li><li>页面重新渲染</li><li>清除friend.id=1的绑定</li><li>替friend.id=2的朋友注册</li><li>...</li></ol><p>怎么跳过一些不必要的副作用函数</p><p>按照上一节的思路，每次重新渲染都要执行一遍这些副作用函数，显然是不经济的。怎么跳过一些不必要的计算呢？我们只需要给useEffect传第二个参数即可。用第二个参数来告诉react只有当这个参数的值发生改变时，才执行我们传的副作用函数（第一个参数）。</p><p></p><pre><code><span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">useEffect</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span> <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=&gt;</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n  document<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>title <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=</span> <span class=\"token template-string\" style=\"box-sizing: border-box;\"><span class=\"token template-punctuation string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">`</span><span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">You clicked </span><span class=\"token interpolation\" style=\"box-sizing: border-box;\"><span class=\"token interpolation-punctuation punctuation\" style=\"box-sizing: border-box;\">${</span>count<span class=\"token interpolation-punctuation punctuation\" style=\"box-sizing: border-box;\">}</span></span><span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\"> times</span><span class=\"token template-punctuation string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">`</span></span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n<span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">,</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">[</span>count<span class=\"token punctuation\" style=\"box-sizing: border-box;\">]</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span> <span class=\"token comment\" style=\"box-sizing: border-box; color: rgb(153, 153, 153);\">// 只有当count的值发生变化时，才会重新执行`document.title`这一句</span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"box-sizing: border-box; position: absolute; pointer-events: none; top: 0px; left: -3.8em; width: 3em; letter-spacing: -1px; border-right: 1px solid rgb(153, 153, 153); user-select: none;\"></span></code></pre><p>当我们第二个参数传一个空数组[]时，其实就相当于只在首次渲染的时候执行。也就是componentDidMount加componentWillUnmount的模式。不过这种用法可能带来bug，少用。</p><p>还有哪些自带的Effect Hooks?</p><p>除了上文重点介绍的useState和useEffect，react还给我们提供来很多有用的hooks：</p><ul><li>useContext</li><li>useReducer</li><li>useCallback</li><li>useMemo</li><li>useRef</li><li>useImperativeMethods</li><li>useMutationEffect</li><li>useLayoutEffect<br>我不再一一介绍，大家自行去查阅官方文档。</li></ul><p>怎么写自定义的Effect Hooks?</p><p>为什么要自己去写一个Effect Hooks? 这样我们才能把可以复用的逻辑抽离出来，变成一个个可以随意插拔的“插销”，哪个组件要用来，我就插进哪个组件里，so easy！看一个完整的例子，你就明白了。</p><p>比如我们可以把上面写的FriendStatus组件中判断朋友是否在线的功能抽出来，新建一个useFriendStatus的hook专门用来判断某个id是否在线。</p><p></p><pre><code><span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">import</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span> useState<span class=\"token punctuation\" style=\"box-sizing: border-box;\">,</span> useEffect <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span> <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">from</span> <span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">'react'</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n\n<span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">function</span> <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">useFriendStatus</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token parameter\" style=\"box-sizing: border-box;\">friendID</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n  <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">const</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">[</span>isOnline<span class=\"token punctuation\" style=\"box-sizing: border-box;\">,</span> setIsOnline<span class=\"token punctuation\" style=\"box-sizing: border-box;\">]</span> <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=</span> <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">useState</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">null</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n\n  <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">function</span> <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">handleStatusChange</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token parameter\" style=\"box-sizing: border-box;\">status</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n    <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">setIsOnline</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span>status<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>isOnline<span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n  <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span>\n\n  <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">useEffect</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span> <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=&gt;</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n    ChatAPI<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span><span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">subscribeToFriendStatus</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span>friendID<span class=\"token punctuation\" style=\"box-sizing: border-box;\">,</span> handleStatusChange<span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n    <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">return</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span> <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=&gt;</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n      ChatAPI<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span><span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">unsubscribeFromFriendStatus</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span>friendID<span class=\"token punctuation\" style=\"box-sizing: border-box;\">,</span> handleStatusChange<span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n    <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n  <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n\n  <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">return</span> isOnline<span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n<span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"box-sizing: border-box; position: absolute; pointer-events: none; top: 0px; left: -3.8em; width: 3em; letter-spacing: -1px; border-right: 1px solid rgb(153, 153, 153); user-select: none;\"></span></code></pre><p>这时候FriendStatus组件就可以简写为：</p><p></p><pre><code><span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">function</span> <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">FriendStatus</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token parameter\" style=\"box-sizing: border-box;\">props</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n  <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">const</span> isOnline <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=</span> <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">useFriendStatus</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span>props<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>friend<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>id<span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n\n  <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">if</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span>isOnline <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">===</span> <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">null</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n    <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">return</span> <span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">'Loading...'</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n  <span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span>\n  <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">return</span> isOnline <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">?</span> <span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">'Online'</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">:</span> <span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">'Offline'</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n<span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"box-sizing: border-box; position: absolute; pointer-events: none; top: 0px; left: -3.8em; width: 3em; letter-spacing: -1px; border-right: 1px solid rgb(153, 153, 153); user-select: none;\"></span></code></pre><p><br></p><p>简直Perfect！假如这个时候我们又有一个朋友列表也需要显示是否在线的信息：</p><p></p><pre><code><span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">function</span> <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">FriendListItem</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span><span class=\"token parameter\" style=\"box-sizing: border-box;\">props</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>\n  <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">const</span> isOnline <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">=</span> <span class=\"token function\" style=\"box-sizing: border-box; color: rgb(240, 141, 73);\">useFriendStatus</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span>props<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>friend<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>id<span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n  <span class=\"token keyword\" style=\"box-sizing: border-box; color: rgb(204, 153, 205);\">return</span> <span class=\"token punctuation\" style=\"box-sizing: border-box;\">(</span>\n    <span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&lt;</span>li</span> <span class=\"token attr-name\" style=\"box-sizing: border-box;\">style</span><span class=\"token script language-javascript\" style=\"box-sizing: border-box;\"><span class=\"token script-punctuation punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">=</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">{</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">{</span> color<span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">:</span> isOnline <span class=\"token operator\" style=\"box-sizing: border-box; color: rgb(103, 205, 204);\">?</span> <span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">'green'</span> <span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">:</span> <span class=\"token string\" style=\"box-sizing: border-box; color: rgb(126, 198, 153);\">'black'</span> <span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">}</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">}</span></span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span><span class=\"token plain-text\" style=\"box-sizing: border-box;\">\n      </span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">{</span>props<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>friend<span class=\"token punctuation\" style=\"box-sizing: border-box;\">.</span>name<span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span><span class=\"token plain-text\" style=\"box-sizing: border-box;\">\n    </span><span class=\"token tag\" style=\"box-sizing: border-box; color: rgb(226, 119, 122);\"><span class=\"token tag\" style=\"box-sizing: border-box;\"><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\"><!--</span-->li</span><span class=\"token punctuation\" style=\"box-sizing: border-box; color: rgb(204, 204, 204);\">&gt;</span></span>\n  <span class=\"token punctuation\" style=\"box-sizing: border-box;\">)</span><span class=\"token punctuation\" style=\"box-sizing: border-box;\">;</span>\n<span class=\"token punctuation\" style=\"box-sizing: border-box;\">}</span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"box-sizing: border-box; position: absolute; pointer-events: none; top: 0px; left: -3.8em; width: 3em; letter-spacing: -1px; border-right: 1px solid rgb(153, 153, 153); user-select: none;\"></span></span></code></pre><p>简直Fabulous!</p>","excerpt":"[转自：https://www.jianshu.com/p/97b6259f9773]React是现在最流行的前端框架之一，它的轻量化，组件化，单向数据流等特性把前端引入了一个新的高度，现在它又引入的Hooks，一个神奇的东东，来看一看。你还在为该使用无状态组件（Function）还是有状态组件（Class）而烦恼吗？——拥有了hooks，你再也不需要写Class了，你的所有组件都将是Function。你还在为搞不清使用哪个生命周期钩子函数而日夜难眠吗？——拥有了Hooks，生命周期钩子函数可以先丢一边了。你在还在为组件中的this指向而晕头转向吗？——","title":"React 新特性——React Hooks","author":"老鼠AI大米_Java全栈","type":"tech","en_gallery":false,"enable":true,"tag":["前端","React"],"img":[],"thumb":[],"mid":[],"raw":[],"createdAt":"2020-04-27T08:07:22.720Z","updatedAt":"2020-05-14T10:21:04.827Z","pv_count":1166,"article_id":"5ea692ba950d432b5b7e4634","id":"5ea692ba950d432b5b7e4634"},{"content":"<h1><br></h1><p>可以像FIS一样，具有模块化的前端目录结构。</p><p>基于gulp，简单、灵活，容易扩展和修改，懂点gulp的童鞋都可以自己修改、使用、组合。</p><p>不需要任何服务端的整合工作，这个与FIS有很大不同，不需要修改服务端代码来适配，就像正常的html一样，去引用你的js、css、img、fonts等资源，无侵入。</p><p>整合SCSS ES6 Browserify|cssnano|uglify|imagmein|rev等前端常用套件，同时有监视文件变动功能(watch)，可配置的发布目录、资源目录、CDN等，方便开发，简单易用，一站式搞定。</p><p><br></p><p><br>更新说明：</p><p><br></p><pre><code class=\"lang-bash\">gulpman 1.4.6版本更新：\n新增支持cdn_prefix的数组/函数/字符串传参方式，更灵活和强大\n新增支持内联嵌入CSS/JS到html。 只需要再url后面添加 ?_gm_inline\n完善内联资源嵌入后的自动更新引用文件(html和CSS)\n完善文档\n</code></pre><pre><code>gulpman 1.3.6版本更新：\n\n新增对React/jsx支持，可以直接写ReactJS了</code></pre><pre><code>gulpman 1.3.3版本更新：\n\n1、新增对复杂目录和多级目录设定支持:\n比如下面这种模板、静态文件复杂的、多级的路径：\ngulpman.config({\n&nbsp; &nbsp; 'components': 'components/cc',\n&nbsp; &nbsp; 'runtime_views': 'runtime_views/rv',\n&nbsp; &nbsp; 'dist_views': 'dist_views/dv/dv',\n&nbsp; &nbsp; 'runtime_assets': 'runtime_assets/ra/ra',\n&nbsp; &nbsp; 'dist_assets': 'dist_assets/da'\n&nbsp; &nbsp;&nbsp;\n})\n\n2、增加彩色log\n\n3、增加base64关联的资源文件的自动关联编译，比如跟这个base64图片有关的html、css都会自动编译(监视模式下)\n</code></pre><p><br></p><p><br></p><p>先来个大致的介绍：</p><ul><li>使用gulpman按照模块划分后，模块根目录可以是<code>./components</code>(默认，可配置)，如果你有个模块是foo，那么应该有如下目录：<code>./components/foo</code>，然后跟foo模块相关的<code>html|js|css|fonts|image</code>等资源文件都放到<code>foo</code>下，这个结构下，做开发时非常清晰、高效，便于模块组织、资源定位等。</li><li>通过<code>gm:publish</code>命令构建后，会自动生成模板<code>views</code>目录，和静态资源<code>assets</code>目录。</li></ul><p><span style=\"color: rgb(51, 51, 51);\"><br></span></p><p><span style=\"color: rgb(51, 51, 51);\"><br></span></p><p><span style=\"color: rgb(51, 51, 51);\">Github源码： <a href=\"https://github.com/xunuoi/gulpman\">https://github.com/xunuoi/gulpman</a></span></p><p><br></p><p><br></p><h3><a href=\"https://github.com/xunuoi/gulpman#introduction-说明\"></a>Introduction 说明</h3><ul><li>支持Mac、Linux环境下安装、使用</li><li>Windows环境未做测试，由于安装脚本使用到shell，windows不支持sh，可能需要手动安装gulp-sass等模块。</li></ul><h3><br></h3><h3><a href=\"https://github.com/xunuoi/gulpman#install-安装\"></a>Install 安装</h3><p>cd into your project dir and install:</p><pre><code class=\"lang-bash\">npm install gulpman --save-dev</code></pre><h3><br></h3><h3><a href=\"https://github.com/xunuoi/gulpman#usage-使用\"></a>Usage 使用说明</h3><h4><br></h4><h4><a href=\"https://github.com/xunuoi/gulpman#in-your-gulpfile\"></a>一、In Your gulpfile:</h4><p>只需要require gulpman模块，就会自动加载gm:publish、gm:develop（开发监视模式）等预置的task，使用时在命令行直接输入gulp gm:publish即可执行</p><p><br></p><pre><code class=\"lang-js\"><span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">/**</span>\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\"> * Gulpfile.js</span>\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\"> */</span>\n\n\n<span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">var</span> gulp <span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">=</span> <span class=\"pl-c1\" style=\"box-sizing: border-box; color: rgb(0, 134, 179);\">require</span>(<span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>gulp<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>),\n    gman <span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">=</span> <span class=\"pl-c1\" style=\"box-sizing: border-box; color: rgb(0, 134, 179);\">require</span>(<span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>gulpman<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>)\n\n\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// your other tasks ...你的其他task\n\n</span>\n\n\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// 设置路径、CDN、资源URL前缀等，API超级简单。\n// 你也可以不设置，全部采用默认值!</span>\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// if you want to set the dir, you can use config API:</span>\n\n<span class=\"pl-smi\" style=\"box-sizing: border-box;\">gman</span>.<span class=\"pl-en\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">config</span>({\n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// 是否使用绝对路径，默认true,推荐使用，方便服务器配置。比如`/static/home/main.js`这种风格。</span>\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// 如果is_absolute是false, 那么可能是`../../assets/static/home/main.js`这种风格。</span>\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// 具体取决于项目情况、服务端配置等。</span>\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// if set the assets url prefix as absolute or relative, default: true</span>\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>is_absolute<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-c1\" style=\"box-sizing: border-box; color: rgb(0, 134, 179);\">true</span>,\n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// cdn prefix 配置CDN</span>\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>cdn_prefix<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>, \n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// 配置资源URL前缀，建议 /xxx这种</span>\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// usually set as /static, this involves the server config ,such as the static path of nginx</span>\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>url_prefix<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>/static<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span> \n\n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// 模块COMPONENTS目录，同一个模块的html和资源文件在一起。默认 'components'即可</span>\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>components<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>components<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>,\n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// develop和publish下的views目录，跟服务端框架的views目录配置一致，比如express</span>\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>runtime_views<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>views<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>,\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>dist_views<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>views_dist<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>,\n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// develop和publish下的assets静态目录，跟服务器配置有关，比如nginx的static目录指向</span>\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>runtime_assets<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>assets<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>,\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>dist_assets<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>assets_dist<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>,\n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// 第三方JS类库、模块的目录，推荐设置为`lib`或`bower_components`（这样bower可以直接安装到这个目录）</span>\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// 这个目录默认打包时为全局模块目录，可以直接`require('xxx')`，而不用加相对路径</span>\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// the js library dir, set as a global module. Also you can set as bower_components</span>\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>lib<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>lib<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>, \n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// 可以添加一个自定的全局模块目录，该目录下的js模块，也作为全局模块来require，不需要相对路径。</span>\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// the global module dir</span>\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>global<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>common<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span> \n})\n\n</code></pre><h4><br></h4><h4><br></h4><h4>二、全局模块介绍：</h4><p><br></p><p>1. config的配置中，lib和global都是全局模块目录。举个例子说明：你的components/lib目录下有一个模块 foo.js，就是： components/lib/foo.js，那么你在你的es6文件中，就可以这样使用：` import foo from 'foo' `，不需要写成 ` import foo from '../lib/foo' `。&nbsp;</p><p>2. 同理global那个配置也是这样的，推荐将lib目录设置成跟bower一致的，全部来存放第三方类库，而global设置的目录，比如common，可以存放自己的 公用模块。</p><p>3. 这样开发会更加灵活、方便。注意全局模块不要用同名冲突。</p><p><br></p><h4><br></h4><h4><a href=\"https://github.com/xunuoi/gulpman#in-your-cli\"></a>三、In Your CLI 命令行中调用:</h4><p>就是普通的调用gulp 的task</p><pre><code class=\"lang-bash\"><span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\"># 初始化目录，建立components目录并添加一份html的demo文件</span>\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\"># init components dir and a html demo</span>\ngulp gm:init\n\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\"># publish 发布资源，包括合并、压缩资源、rev产生MD5等</span>\ngulp gm:publish\n\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\"># develop and watch 开发模式，监视相关文件变动，增量更新</span>\ngulp gm:develop\n\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\"># clean 清理构建输出的目录和文件</span>\ngulp gm:clean\n\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\"># 编译输出一份运行时资源文件，但是不进入监视状态</span>\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\"># compile for develop, not watch</span>\ngulp gm:compile\n</code></pre>","excerpt":"可以像FIS一样，具有模块化的前端目录结构。基于gulp，简单、灵活，容易扩展和修改，懂点gulp的童鞋都可以自己修改、使用、组合。不需要任何服务端的整合工作，这个与FIS有很大不同，不需要修改服务端代码来适配，就像正常的html一样，去引用你的js、css、img、fonts等资源，无侵入。整合SCSS ES6 Browserify|cssnano|uglify|imagmein|rev等前端常用套件，同时有监视文件变动功能(watch)，可配置的发布目录、资源目录、CDN等，方便开发，简单易用，一站式搞定。更新说明：gulpman 1.4.6版本更新","title":"Gulpan-简单灵活的模块化前端解决方案!","author":"Cloud","type":"tech","en_gallery":false,"enable":true,"tag":["前端"],"img":[],"thumb":[],"mid":[],"raw":[],"createdAt":"2016-01-23T10:11:15.235Z","updatedAt":"2016-02-05T08:19:47.223Z","pv_count":3662,"article_id":"56a351c3e48d2d05682aa0ac","id":"56a351c3e48d2d05682aa0ac"},{"content":"<p>gulp的dest，路径问题，新手可能经常不太明白这个路径最后是怎么决定的：</p><p><br></p><p>通过指定<code>gulp.src()</code>方法配置参数中的<code>base</code>属性，我们可以更灵活的来改变<code>gulp.dest()</code>生成的文件路径。<br>当我们没有在<code>gulp.src()</code>方法中配置<code>base</code>属性时，<code>base</code>的默认值为通配符开始出现之前那部分路径，例如：</p><pre><code>gulp.src(<span class=\"hljs-string\" style=\"color: rgb(163, 21, 21);\">'app/src/**/*.css'</span>) <span class=\"hljs-comment\" style=\"color: green;\">//此时base的值为 app/src</span></code></pre><p>上面我们说的<code>gulp.dest()</code>所生成的文件路径的规则，其实也可以理解成，用我们给<code>gulp.dest()</code>传入的路径替换掉<code>gulp.src()</code>中的<code>base</code>路径，最终得到生成文件的路径。</p><pre><code>gulp.src(<span class=\"hljs-string\" style=\"color: rgb(163, 21, 21);\">'app/src/**/*.css'</span>) /<span class=\"hljs-regexp\">/此时base的值为app/src</span>,也就是说它的base路径为app/src\n     /<span class=\"hljs-regexp\">/设该模式匹配到了文件 app/src</span><span class=\"hljs-regexp\">/css/normal</span>.css\n    .pipe(gulp.dest(<span class=\"hljs-string\" style=\"color: rgb(163, 21, 21);\">'dist'</span>)) /<span class=\"hljs-regexp\">/用dist替换掉base路径，最终得到 dist/css</span><span class=\"hljs-regexp\">/normal.css</span></code></pre><p>所以改变base路径后，<code>gulp.dest()</code>生成的文件路径也会改变</p><pre><code>gulp.src(script<span class=\"hljs-regexp\">/lib/</span>*.js) <span class=\"hljs-regexp\">//</span>没有配置base参数，此时默认的base路径为script/lib\n    <span class=\"hljs-regexp\">//</span>假设匹配到的文件为script/lib/jquery.js\n    .pipe(gulp.dest(<span class=\"hljs-string\" style=\"color: rgb(163, 21, 21);\">'build'</span>)) <span class=\"hljs-regexp\">//</span>生成的文件路径为 build/jquery.js\n\ngulp.src(script<span class=\"hljs-regexp\">/lib/</span>*.js, {base:<span class=\"hljs-string\" style=\"color: rgb(163, 21, 21);\">'script'</span>}) <span class=\"hljs-regexp\">//</span>配置了base参数，此时base路径为script\n    <span class=\"hljs-regexp\">//</span>假设匹配到的文件为script/lib/jquery.js\n    .pipe(gulp.dest(<span class=\"hljs-string\" style=\"color: rgb(163, 21, 21);\">'build'</span>)) <span class=\"hljs-regexp\">//</span>此时生成的文件路径为 build/lib/jquery.js    </code></pre><p>用<code>gulp.dest()</code>把文件流写入文件后，文件流仍然可以继续使用。</p>","excerpt":"gulp的dest，路径问题，新手可能经常不太明白这个路径最后是怎么决定的：通过指定gulp.src()方法配置参数中的base属性，我们可以更灵活的来改变gulp.dest()生成的文件路径。当我们没有在gulp.src()方法中配置base属性时，base的默认值为通配符开始出现之前那部分路径，例如：gulp.src('app/src/**/*.css') //此时base的值为 app/src上面我们说的gulp.dest()所生成的文件路径的规则，其实也可以理解成，用我们给gulp.dest()传入的路径替换掉gulp.src()中的base路径","title":"gulp.dest的文件路径说明","author":"Cloud","type":"tech","en_gallery":false,"enable":true,"tag":["前端"],"img":[],"thumb":[],"mid":[],"raw":[],"createdAt":"2016-01-20T03:32:58.208Z","updatedAt":"2016-01-20T03:33:20.277Z","article_id":"569effeae48d2d05682aa0aa","pv_count":1494,"id":"569effeae48d2d05682aa0aa"},{"content":"<p>Sails近期好久没有更新了，听说维护的人员有几个离开了，准备另起炉灶。。。我了去个去。。。</p><p>一直觉着Sails整体还是不错的，有些小地方比如ORM对url的映射有些安全性问题、blueprint过于随意、前端构建不够好等地方需要提高外，基本的功能感觉是NodeJS里面比较靠谱的、全面的，但是现在。。。</p><p><br></p><p>首先Sails在Node 0.12.x版本上，会有内存泄露的问题（并非是github上issue提到的关闭.saisrc中grunt：false就可以解决的），默认的home页 ，多次刷新后，也会看到内存占用持续涨。github上有提到这是nodejs 0.12.x版本本身的问题，说这个node版本是允许尽量多的占用内存的，并且gc不会很主动的去回收。。。</p><p>另外如果仅仅依靠新版本 Node 4/5，虽然对于大多数es6语法支持了，对于现在的export、async/await等都不支持。。。还是有些缺陷，希望Node 5甚至6早些release<br></p><p><br></p><p>感觉这样下去，Sails也就很快没落无声了，没啥活跃社区，N久没更新主体，也没有跟上Node和Express最新版本。。。真可惜。。。</p><p><br></p><p>另外最近babel发的6，变成平台了，要跟gulp、grunt竞争么。。。</p><p>其实gulp已经很好了，只是生态圈还需要更多模块去填充。。。</p><p>babel6的说明中写的，他们感觉babel不仅仅可以做转换工具，也可以做平台，做css、js、img等处理。。。</p><p>醉了。。。大哥你就好好做转换多好，平台够多了，现在需要的就是大家写一些好的组件填充进去，您又要搞平台。。。</p><p>transfer es6到es6，babel还是有很多地方可以提高、简化的，再继续做下去很好的。。。现在都成插件了，不知道以后啥情况。。。</p><p><br></p><p>近期更新了服务器到 node 4.x，来解决内存泄露问题。这个时候生成验证码的ccap不好用了，要么重新npm安装，要么复制一份编译好的扔到node_modules，服务器是gcc是4.4.7，升级到gcc 4.8走了一遍，安装始终有问题，去config.log中查看，将报错找不到的模块编译安装了，还不行。。。囧，最后还是复制了一份编译好的ccap扔到服务器node_modules上了。</p>","excerpt":"Sails近期好久没有更新了，听说维护的人员有几个离开了，准备另起炉灶。。。我了去个去。。。一直觉着Sails整体还是不错的，有些小地方比如ORM对url的映射有些安全性问题、blueprint过于随意、前端构建不够好等地方需要提高外，基本的功能感觉是NodeJS里面比较靠谱的、全面的，但是现在。。。首先Sails在Node 0.12.x版本上，会有内存泄露的问题（并非是github上issue提到的关闭.saisrc中grunt：false就可以解决的），默认的home页 ，多次刷新后，也会看到内存占用持续涨。github上有提到这是nodejs 0.","title":"Sails 不怎么维护了？","author":"Cloud","type":"essay","en_gallery":false,"enable":true,"tag":["前端","Web"],"img":[],"thumb":[],"mid":[],"raw":[],"createdAt":"2015-12-31T13:55:32.162Z","updatedAt":"2016-01-05T07:30:25.997Z","pv_count":1162,"article_id":"568533d4c03d73ad31bb7bce","id":"568533d4c03d73ad31bb7bce"},{"content":"<p>Angular 1.x 看着可能更像是 java 系的框架爱。在带来了数据绑定这个先进生产力代表的同时，又带入了一大堆前端本来就不需要的包袱。指令、服务、scope等使用略微繁琐。<br></p><p>Vue 只专注于View-Model,其他的控制权、策略制定都交给开发者，思路很清晰<br></p><p>个人觉着，Angular最大的贡献就是推广了双向绑定，极大提高了富数据业务的生产力，这是核心，其他附带的特性和功能，各有评判吧~</p><p>React，则是很好的提供了一个组件化、状态维护的技术思路~Virtual-Dom的概念，可以有很多探索和前端之外的应用</p><p>Avalon的话，自己没有实际用过，他的数据绑定实现细节跟Angular略有不同，兼容性更好（兼容IE6），但是总的来时还是借鉴了ng的思路。</p><p>关于兼容性，<a href=\"//www.zhihu.com/people/c11336b8607d86bc9090bed90757a34c\">@玉伯</a>&nbsp;说过一句话，我觉得说的非常好“这年头，支持 IE6、7 早就不再是特性，而是耻辱。努力推动支付宝全面不支持 IE6、7，期待更多兄弟加盟”。</p><p>我还是蛮支持这个观点的，前端发展本来就滞后于后端的技术，很多现在前端圈内觉着很新的理念、技术思路、方案、语法特性，在后端N早就实现了。浏览器的发展是很大的一个局限，让IE 6\\7\\8甚至9，早点寿终正寝，未尝不是一件好事~</p>","excerpt":"Angular 1.x 看着可能更像是 java 系的框架爱。在带来了数据绑定这个先进生产力代表的同时，又带入了一大堆前端本来就不需要的包袱。指令、服务、scope等使用略微繁琐。Vue 只专注于View-Model,其他的控制权、策略制定都交给开发者，思路很清晰个人觉着，Angular最大的贡献就是推广了双向绑定，极大提高了富数据业务的生产力，这是核心，其他附带的特性和功能，各有评判吧~React，则是很好的提供了一个组件化、状态维护的技术思路~Virtual-Dom的概念，可以有很多探索和前端之外的应用Avalon的话，自己没有实际用过，他的数据绑定","title":"关于Angular、Vue、React的一些见解","author":"Cloud","type":"tech","en_gallery":false,"enable":true,"tag":["前端","Web"],"img":[],"thumb":[],"mid":[],"raw":[],"createdAt":"2015-12-25T06:26:10.381Z","updatedAt":"2015-12-25T06:26:33.680Z","article_id":"567ce182dbde3d97180380df","pv_count":1164,"id":"567ce182dbde3d97180380df"},{"content":"<h1><span style=\"color: rgb(51, 51, 51);\"><br></span></h1><h1><span style=\"color: rgb(51, 51, 51);\">转自：<a taget=\"_blank\" href=\"http://www.ruanyifeng.com/blog/2015/09/web-page-performance-in-depth.html\" rel=\"nofollow\">http://www.ruanyifeng.com/blog/2015/09/web-page-performance-in-depth.html</a></span><br></h1><p>作者： 阮一峰&nbsp;<br></p><p><br></p><p><br></p><p>你遇到过性能很差的网页吗？</p><p>这种网页响应非常缓慢，占用大量的CPU和内存，浏览起来常常有卡顿，页面的动画效果也不流畅。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091508.jpg\" alt=\"\"></p><p>你会有什么反应？我猜想，大多数用户会关闭这个页面，改为访问其他网站。作为一个开发者，肯定不愿意看到这种情况，那么怎样才能提高性能呢？</p><p>本文将详细介绍性能问题的出现原因，以及解决方法。</p><h2>一、网页生成的过程</h2><p>要理解网页性能为什么不好，就要了解网页是怎么生成的。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091501.png\" alt=\"\"></p><p>网页的生成过程，大致可以分成五步。</p><blockquote><ol><li>HTML代码转化成DOM</li><li>CSS代码转化成CSSOM（CSS Object Model）</li><li>结合DOM和CSSOM，生成一棵渲染树（包含每个节点的视觉信息）</li><li>生成布局（layout），即将所有渲染树的所有节点进行平面合成</li><li>将布局绘制（paint）在屏幕上</li></ol></blockquote><p>这五步里面，第一步到第三步都非常快，耗时的是第四步和第五步。</p><p>\"生成布局\"（flow）和\"绘制\"（paint）这两步，合称为\"渲染\"（render）。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091502.png\" alt=\"\"></p><h2>二、重排和重绘</h2><p>网页生成的时候，至少会渲染一次。用户访问的过程中，还会不断重新渲染。</p><p>以下三种情况，会导致网页重新渲染。</p><blockquote><ul><li>修改DOM</li><li>修改样式表</li><li>用户事件（比如鼠标悬停、页面滚动、输入框键入文字、改变窗口大小等等）</li></ul></blockquote><p>重新渲染，就需要重新生成布局和重新绘制。前者叫做\"重排\"（reflow），后者叫做\"重绘\"（repaint）。</p><p>需要注意的是，\"重绘\"不一定需要\"重排\"，比如改变某个网页元素的颜色，就只会触发\"重绘\"，不会触发\"重排\"，因为布局没有改变。但是，\"重排\"必然导致\"重绘\"，比如改变一个网页元素的位置，就会同时触发\"重排\"和\"重绘\"，因为布局改变了。</p><h2>三、对于性能的影响</h2><p>重排和重绘会不断触发，这是不可避免的。但是，它们非常耗费资源，是导致网页性能低下的根本原因。</p><p>提高网页性能，就是要降低\"重排\"和\"重绘\"的频率和成本，尽量少触发重新渲染。</p><p>前面提到，DOM变动和样式变动，都会触发重新渲染。但是，浏览器已经很智能了，会尽量把所有的变动集中在一起，排成一个队列，然后一次性执行，尽量避免多次重新渲染。</p><blockquote><p><br></p><pre><code>div<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>color <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">'blue'</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\ndiv<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>marginTop <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">'30px'</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n</code></pre><p><br></p></blockquote><p>上面代码中，div元素有两个样式变动，但是浏览器只会触发一次重排和重绘。</p><p>如果写得不好，就会触发两次重排和重绘。</p><blockquote><p><br></p><pre><code class=\"lang-js\">div<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>color <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">'blue'</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n<span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">var</span> margin <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">parseInt<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>div<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>marginTop<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\ndiv<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>marginTop <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span>margin <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">10</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">'px'</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n</code></pre><p><br></p></blockquote><p>上面代码对div元素设置背景色以后，第二行要求浏览器给出该元素的位置，所以浏览器不得不立即重排。</p><p>一般来说，样式的写操作之后，如果有下面这些属性的读操作，都会引发浏览器立即重新渲染。</p><blockquote><ul><li>offsetTop/offsetLeft/offsetWidth/offsetHeight</li><li>scrollTop/scrollLeft/scrollWidth/scrollHeight</li><li>clientTop/clientLeft/clientWidth/clientHeight</li><li>getComputedStyle()</li></ul></blockquote><p>所以，从性能角度考虑，尽量不要把读操作和写操作，放在一个语句里面。</p><blockquote><p><br></p><pre><code class=\"lang-js\"><span class=\"token comment\" spellcheck=\"true\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: slategray;\">\n// bad\n</span>div<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>left <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> div<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>offsetLeft <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">10</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">\"px\"</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\ndiv<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>top <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> div<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>offsetTop <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">10</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">\"px\"</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n<span class=\"token comment\" spellcheck=\"true\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: slategray;\">\n// good\n</span><span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">var</span> left <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> div<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>offsetLeft<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n<span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">var</span> top  <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> div<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>offsetTop<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\ndiv<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>left <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> left <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">10</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">\"px\"</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\ndiv<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>top <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> top <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">10</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">\"px\"</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n</code></pre><p><br></p></blockquote><p>一般的规则是：</p><blockquote><ul><li>样式表越简单，重排和重绘就越快。</li><li>重排和重绘的DOM元素层级越高，成本就越高。</li><li>table元素的重排和重绘成本，要高于div元素</li></ul></blockquote><h2>四、提高性能的九个技巧</h2><p>有一些技巧，可以降低浏览器重新渲染的频率和成本。</p><p>第一条是上一节说到的，DOM 的多个读操作（或多个写操作），应该放在一起。不要两个读操作之间，加入一个写操作。</p><p>第二条，如果某个样式是通过重排得到的，那么最好缓存结果。避免下一次用到的时候，浏览器又要重排。</p><p>第三条，不要一条条地改变样式，而要通过改变class，或者csstext属性，一次性地改变样式。</p><blockquote><p><br></p><pre><code class=\"lang-js\"><span class=\"token comment\" spellcheck=\"true\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: slategray;\">\n// bad\n</span><span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">var</span> left <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">10</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n<span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">var</span> top <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">10</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\nel<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>left <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> left <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">\"px\"</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\nel<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>top  <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> top  <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">\"px\"</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n<span class=\"token comment\" spellcheck=\"true\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: slategray;\">\n// good \n</span>el<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>className <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span><span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">\" theclassname\"</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n<span class=\"token comment\" spellcheck=\"true\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: slategray;\">\n// good\n</span>el<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>cssText <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span><span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">\"; left: \"</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> left <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">\"px; top: \"</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> top <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">\"px;\"</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n</code></pre><p><br></p></blockquote><p>第四条，尽量使用离线DOM，而不是真实的网面DOM，来改变元素样式。比如，操作Document Fragment对象，完成后再把这个对象加入DOM。再比如，使用 cloneNode() 方法，在克隆的节点上进行操作，然后再用克隆的节点替换原始节点。</p><p>第五条，先将元素设为<code>display: none</code>（需要1次重排和重绘），然后对这个节点进行100次操作，最后再恢复显示（需要1次重排和重绘）。这样一来，你就用两次重新渲染，取代了可能高达100次的重新渲染。</p><p>第六条，position属性为<code>absolute</code>或<code>fixed</code>的元素，重排的开销会比较小，因为不用考虑它对其他元素的影响。</p><p>第七条，只在必要的时候，才将元素的display属性为可见，因为不可见的元素不影响重排和重绘。另外，<code>visibility : hidden</code>的元素只对重绘有影响，不影响重排。</p><p>第八条，使用虚拟DOM的脚本库，比如React等。</p><p>第九条，使用 window.requestAnimationFrame()、window.requestIdleCallback() 这两个方法调节重新渲染（详见后文）。</p><h2>五、刷新率</h2><p>很多时候，密集的重新渲染是无法避免的，比如scroll事件的回调函数和网页动画。</p><p>网页动画的每一帧（frame）都是一次重新渲染。每秒低于24帧的动画，人眼就能感受到停顿。一般的网页动画，需要达到每秒30帧到60帧的频率，才能比较流畅。如果能达到每秒70帧甚至80帧，就会极其流畅。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091509.jpg\" alt=\"\"></p><p>大多数显示器的刷新频率是60Hz，为了与系统一致，以及节省电力，浏览器会自动按照这个频率，刷新动画（如果可以做到的话）。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091510.jpg\" alt=\"\"></p><p>所以，如果网页动画能够做到每秒60帧，就会跟显示器同步刷新，达到最佳的视觉效果。这意味着，一秒之内进行60次重新渲染，每次重新渲染的时间不能超过16.66毫秒。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091511.png\" alt=\"\"></p><p>一秒之间能够完成多少次重新渲染，这个指标就被称为\"刷新率\"，英文为FPS（frame per second）。60次重新渲染，就是60FPS。</p><p>如果想达到60帧的刷新率，就意味着JavaScript线程每个任务的耗时，必须少于16毫秒。一个解决办法是使用Web Worker，主线程只用于UI渲染，然后跟UI渲染不相干的任务，都放在Worker线程。</p><h2>六、开发者工具的Timeline面板</h2><p>Chrome浏览器开发者工具的Timeline面板，是查看\"刷新率\"的最佳工具。这一节介绍如何使用这个工具。</p><p>首先，按下 F12 打开\"开发者工具\"，切换到Timeline面板。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091512.png\" alt=\"\"></p><p>左上角有一个灰色的圆点，这是录制按钮，按下它会变成红色。然后，在网页上进行一些操作，再按一次按钮完成录制。</p><p>Timeline面板提供两种查看方式：横条的是\"事件模式\"（Event Mode），显示重新渲染的各种事件所耗费的时间；竖条的是\"帧模式\"（Frame Mode），显示每一帧的时间耗费在哪里。</p><p>先看\"事件模式\"，你可以从中判断，性能问题发生在哪个环节，是JavaScript的执行，还是渲染？</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091514.png\" alt=\"\"></p><p>不同的颜色表示不同的事件。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091503.png\" alt=\"\"></p><blockquote><ul><li>蓝色：网络通信和HTML解析</li><li>黄色：JavaScript执行</li><li>紫色：样式计算和布局，即重排</li><li>绿色：重绘</li></ul></blockquote><p>哪种色块比较多，就说明性能耗费在那里。色块越长，问题越大。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091515.png\" alt=\"\"></p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091516.png\" alt=\"\"></p><p>帧模式（Frames mode）用来查看单个帧的耗时情况。每帧的色柱高度越低越好，表示耗时少。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091505.png\" alt=\"\"></p><p>你可以看到，帧模式有两条水平的参考线。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091517.png\" alt=\"\"></p><p>下面的一条是60FPS，低于这条线，可以达到每秒60帧；上面的一条是30FPS，低于这条线，可以达到每秒30次渲染。如果色柱都超过30FPS，这个网页就有性能问题了。</p><p>此外，还可以查看某个区间的耗时情况。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091518.png\" alt=\"\"></p><p>或者点击每一帧，查看该帧的时间构成。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091519.png\" alt=\"\"></p><h2>七、window.requestAnimationFrame()</h2><p>有一些JavaScript方法可以调节重新渲染，大幅提高网页性能。</p><p>其中最重要的，就是 window.requestAnimationFrame() 方法。它可以将某些代码放到下一次重新渲染时执行。</p><blockquote><p><br></p><pre><code class=\"lang-js\"><span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">function</span> <span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">doubleHeight<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>element<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">{</span>\n  <span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">var</span> currentHeight <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> element<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>clientHeight<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n  element<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>height <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span>currentHeight <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">*</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">2</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">'px'</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">}</span>\nelements<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span><span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">forEach<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>doubleHeight<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n</code></pre><p><br></p></blockquote><p>上面的代码使用循环操作，将每个元素的高度都增加一倍。可是，每次循环都是，读操作后面跟着一个写操作。这会在短时间内触发大量的重新渲染，显然对于网页性能很不利。</p><p>我们可以使用<code>window.requestAnimationFrame()</code>，让读操作和写操作分离，把所有的写操作放到下一次重新渲染。</p><blockquote><p><br></p><pre><code><span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">function</span> <span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">doubleHeight<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>element<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">{</span>\n  <span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">var</span> currentHeight <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> element<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>clientHeight<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n  window<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span><span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">requestAnimationFrame<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span><span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">function</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">{</span>\n    element<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>height <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span>currentHeight <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">*</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">2</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">'px'</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n  <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">}</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">}</span>\nelements<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span><span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">forEach<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>doubleHeight<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n</code></pre><p><br></p></blockquote><p>页面滚动事件（scroll）的监听函数，就很适合用 window.requestAnimationFrame() ，推迟到下一次重新渲染。</p><blockquote><p><br></p><pre><code>$<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span>window<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span><span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">on<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span><span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">'scroll'</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">,</span> <span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">function</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">{</span>\n   window<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span><span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">requestAnimationFrame<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>scrollHandler<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">}</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n</code></pre><p><br></p></blockquote><p>当然，最适用的场合还是网页动画。下面是一个旋转动画的例子，元素每一帧旋转1度。</p><blockquote><p><br></p><pre><code><span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">var</span> rAF <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> window<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>requestAnimationFrame<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n\n<span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">var</span> degrees <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">0</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n<span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">function</span> <span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">update<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">{</span>\n  div<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>transform <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">\"rotate(\"</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> degrees <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">\"deg)\"</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n  console<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span><span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">log<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span><span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">'updated to degrees '</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> degrees<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n  degrees <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> degrees <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">1</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n  <span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">rAF<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>update<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">}</span>\n<span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">rAF<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>update<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n</code></pre><p><br></p></blockquote><h2><br></h2><h2><br></h2><h2>八、window.requestIdleCallback()</h2><p>还有一个函数<a href=\"https://w3c.github.io/requestidlecallback/\" target=\"_blank\">window.requestIdleCallback()</a>，也可以用来调节重新渲染。</p><p>它指定只有当一帧的末尾有空闲时间，才会执行回调函数。</p><blockquote><p><br></p><pre><code class=\"lang-js\"><span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">requestIdleCallback<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>fn<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n</code></pre><p><br></p></blockquote><p>上面代码中，只有当前帧的运行时间小于16.66ms时，函数fn才会执行。否则，就推迟到下一帧，如果下一帧也没有空闲时间，就推迟到下下一帧，以此类推。</p><p>它还可以接受第二个参数，表示指定的毫秒数。如果在指定 的这段时间之内，每一帧都没有空闲时间，那么函数fn将会强制执行。</p><blockquote><p><br></p><pre><code class=\"lang-js\"><span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">requestIdleCallback<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>fn<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">,</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">5000</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n</code></pre><p><br></p></blockquote><p>上面的代码表示，函数fn最迟会在5000毫秒之后执行。</p><p>函数 fn 可以接受一个 deadline 对象作为参数。</p><blockquote><p><br></p><pre><code class=\"lang-js\"><span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">requestIdleCallback<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span><span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">function</span> <span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">someHeavyComputation<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>deadline<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">{</span>\n  <span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">while</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span>deadline<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span><span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">timeRemaining<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">&gt;</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">0</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">{</span>\n    <span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">doWorkIfNeeded<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n  <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">}</span>\n\n  <span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">if</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span>thereIsMoreWorkToDo<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">{</span>\n    <span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">requestIdleCallback<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>someHeavyComputation<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n  <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">}</span>\n<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">}</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n</code></pre><p><br></p></blockquote><p>上面代码中，回调函数 someHeavyComputation 的参数是一个 deadline 对象。</p><p>deadline对象有一个方法和一个属性：timeRemaining() 和 didTimeout。</p><p><br></p><p>（1）timeRemaining() 方法</p><p>timeRemaining() 方法返回当前帧还剩余的毫秒。这个方法只能读，不能写，而且会动态更新。因此可以不断检查这个属性，如果还有剩余时间的话，就不断执行某些任务。一旦这个属性等于0，就把任务分配到下一轮<code>requestIdleCallback</code>。</p><p>前面的示例代码之中，只要当前帧还有空闲时间，就不断调用doWorkIfNeeded方法。一旦没有空闲时间，但是任务还没有全执行，就分配到下一轮<code>requestIdleCallback</code>。</p><p><br></p><p>（2）didTimeout属性</p><p>deadline对象的&nbsp;<code>didTimeout</code>&nbsp;属性会返回一个布尔值，表示指定的时间是否过期。这意味着，如果回调函数由于指定时间过期而触发，那么你会得到两个结果。</p><blockquote><ul><li>timeRemaining方法返回0</li><li>didTimeout 属性等于 true</li></ul></blockquote><p>因此，如果回调函数执行了，无非是两种原因：当前帧有空闲时间，或者指定时间到了。</p><blockquote><p><br></p><pre><code class=\"lang-js\"><span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">function</span> myNonEssentialWork <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span>deadline<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">{</span>\n  <span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">while</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span>deadline<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span><span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">timeRemaining<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">&gt;</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">0</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">||</span> deadline<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>didTimeout<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">&amp;&amp;</span> tasks<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>length <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">&gt;</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">0</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span>\n    <span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">doWorkIfNeeded<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n\n  <span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">if</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span>tasks<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>length <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">&gt;</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">0</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span>\n    <span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">requestIdleCallback<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>myNonEssentialWork<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">}</span>\n\n<span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">requestIdleCallback<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>myNonEssentialWork<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">,</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">5000</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n</code></pre><p><br></p></blockquote><p>上面代码确保了，doWorkIfNeeded 函数一定会在将来某个比较空闲的时间（或者在指定时间过期后）得到反复执行。</p><p>requestIdleCallback 是一个很新的函数，刚刚引入标准，目前只有Chrome支持，不过其他浏览器可以用<a href=\"https://gist.github.com/paullewis/55efe5d6f05434a96c36\" target=\"_blank\">垫片库</a>。</p><h2><br></h2><h2><br></h2><h2>九、参考链接</h2><ul><li>Domenico De Felice,&nbsp;<a href=\"http://domenicodefelice.blogspot.sg/2015/08/how-browsers-work.html\" target=\"_blank\">How browsers work</a></li><li>Stoyan Stefanov,&nbsp;<a href=\"http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/\" target=\"_blank\">Rendering: repaint, reflow/relayout, restyle</a></li><li>Addy Osmani,&nbsp;<a href=\"http://addyosmani.com/blog/performance-optimisation-with-timeline-profiles/\" target=\"_blank\">Improving Web App Performance With the Chrome DevTools Timeline and Profiles</a></li><li>Tom Wiltzius,&nbsp;<a href=\"http://www.html5rocks.com/en/tutorials/speed/rendering/\" target=\"_blank\">Jank Busting for Better Rendering Performance</a></li><li>Paul Lewis,&nbsp;<a href=\"https://developers.google.com/web/updates/2015/08/27/using-requestidlecallback?hl=en\" target=\"_blank\">Using requestIdleCallback</a></li></ul><p>（完）</p>","excerpt":"转自：http://www.ruanyifeng.com/blog/2015/09/web-page-performance-in-depth.html作者： 阮一峰 你遇到过性能很差的网页吗？这种网页响应非常缓慢，占用大量的CPU和内存，浏览起来常常有卡顿，页面的动画效果也不流畅。你会有什么反应？我猜想，大多数用户会关闭这个页面，改为访问其他网站。作为一个开发者，肯定不愿意看到这种情况，那么怎样才能提高性能呢？本文将详细介绍性能问题的出现原因，以及解决方法。一、网页生成的过程要理解网页性能为什么不好，就要了解网页是怎么生成的。网页的生成过程，大致可以分","img":["http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091508.jpg","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091501.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091502.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091509.jpg","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091510.jpg","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091511.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091512.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091514.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091503.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091515.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091516.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091505.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091517.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091518.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091519.png"],"title":"网页性能管理详解","author":"阮一峰 ","type":"tech","en_gallery":false,"enable":true,"tag":["前端","Web"],"thumb":["http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091508.jpg","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091501.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091502.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091509.jpg","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091510.jpg","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091511.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091512.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091514.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091503.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091515.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091516.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091505.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091517.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091518.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091519.png"],"mid":["http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091508.jpg","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091501.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091502.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091509.jpg","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091510.jpg","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091511.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091512.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091514.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091503.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091515.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091516.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091505.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091517.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091518.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091519.png"],"raw":["http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091508.jpg","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091501.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091502.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091509.jpg","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091510.jpg","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091511.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091512.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091514.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091503.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091515.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091516.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091505.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091517.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091518.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091519.png"],"createdAt":"2015-12-05T05:08:25.460Z","updatedAt":"2015-12-05T05:11:48.574Z","pv_count":1923,"article_id":"56627149dbde3d97180380d3","id":"56627149dbde3d97180380d3"},{"content":"<p>做h5/web app经常需要做资源预加载，一种是利用H5的manifest的离线存储实现缓存功能，是非定向的，一种是利用js/css来做定向的资源预加载~</p><p>JS的话，经常会用img的src来做文章，写一个简单地图片资源预加载：</p><p><br></p><p>首先定义一个资源组件的格式，这样有N多组件的时候，方便统一维护：&nbsp;</p><pre><code>component1 = {\n&nbsp; &nbsp; 'source': {\n&nbsp; &nbsp; &nbsp; &nbsp; 'type': 'img',\n&nbsp; &nbsp; &nbsp; &nbsp; 'url': ['/static/img/common/loader.gif']\n&nbsp; &nbsp; }\n}</code></pre><p>现在我们简单设置type为img来做为资源类型，然后url是一个数组~这个数组可以是js动态生成、获取的~</p><p><br></p><p>然后就是写一个preloader，需要处理onload的逻辑（但是api没有暴露出去cb找个参数）~</p><p>然后_loader是一个字典，按照类型不同（比如本实例是img），可以挂载不同的处理函数，比较灵活，还可以将这个_loader对象暴露出去封装一个api，让调用者可以修改添加_loader，这样可以自己添加不同类型的资源预加载处理方式。</p><p><br></p><p>然后再做一个listify函数，能实现multi传参~这样调用preload会比较灵活简单~</p><p><br></p><p><b>完整代码：</b></p><pre><code class=\"lang-js\">/**\n&nbsp;* Prelaod Source\n&nbsp;*/\n\n\nlet _loader = {\n\n    img (url, cb) {\n        let img = new Image()\n        img.src = url\n\n        if (img.complete) {\n            if(cb) cb(img)\n        }else {\n            img.onload = function () {\n                if(cb) cb(img)\n                img.onload = null\n            }\n        }\n\n    }\n}\n\n\n//实现multi传参调用\n\nfunction _listfy(_fn){\n    return function(...args){\n        let listParams = [].concat(args),\n            len = listParams.length\n\n        // console.log(listParams)\n\n        for(let i=0;i&lt;len;i++){\n            _fn(listParams[i])\n        }\n\n    }\n}\n\n\nfunction _preload(component) {\n    if(component.source &amp;&amp; \n        component.source.type &amp;&amp; \n        component.source.url){\n\n        setTimeout(()=&gt;{\n            _listfy(_loader[component.source.type])(...component.source.url)\n        }, 500)\n         \n    }\n}\n\n\nlet preload = _listfy(_preload)\n\n\nexport {\n    preload\n}\n<len;i++){ &nbsp;=\"\" _fn(listparams[i])=\"\" }=\"\" function=\"\" _preload(component)=\"\" {=\"\" if(component.source=\"\" &&&nbsp;=\"\" component.source.type=\"\" component.source.url){=\"\" settimeout(()=\"\">\n</len;i++){></code></pre><p><br></p><p><br></p><p>调用preload:</p><pre><code class=\"lang-js\">let c1 = {\n&nbsp; &nbsp; 'source': {\n&nbsp; &nbsp; &nbsp; &nbsp; 'type': 'img',\n&nbsp; &nbsp; &nbsp; &nbsp; 'url': ['/static/img/common/loader.gif']\n&nbsp; &nbsp; }\n}\nlet c2, c3 ....\n\npreload(c1,c2, c3,...)\npreload([c1, c2, c3])</code></pre>","excerpt":"做h5/web app经常需要做资源预加载，一种是利用H5的manifest的离线存储实现缓存功能，是非定向的，一种是利用js/css来做定向的资源预加载~JS的话，经常会用img的src来做文章，写一个简单地图片资源预加载：首先定义一个资源组件的格式，这样有N多组件的时候，方便统一维护： component1 = {    'source': {        'type': 'img',        'url': ['/static/img/common/loader.gif']    }}现在我们简单设置type为img来做为资源类型，然后url","title":"JS做简单地资源预加载","author":"Cloud","type":"tech","en_gallery":false,"enable":true,"tag":["前端","Web"],"img":[],"thumb":[],"mid":[],"raw":[],"createdAt":"2015-11-27T09:57:08.283Z","updatedAt":"2015-12-14T02:52:43.724Z","pv_count":1234,"article_id":"565828f49045a9f3717c0ffd","id":"565828f49045a9f3717c0ffd"}],"prevPage":false,"nextPage":2,"allPages":2,"currentPage":1,"hotArticleList":[{"content":"<h1><br></h1><p>可以像FIS一样，具有模块化的前端目录结构。</p><p>基于gulp，简单、灵活，容易扩展和修改，懂点gulp的童鞋都可以自己修改、使用、组合。</p><p>不需要任何服务端的整合工作，这个与FIS有很大不同，不需要修改服务端代码来适配，就像正常的html一样，去引用你的js、css、img、fonts等资源，无侵入。</p><p>整合SCSS ES6 Browserify|cssnano|uglify|imagmein|rev等前端常用套件，同时有监视文件变动功能(watch)，可配置的发布目录、资源目录、CDN等，方便开发，简单易用，一站式搞定。</p><p><br></p><p><br>更新说明：</p><p><br></p><pre><code class=\"lang-bash\">gulpman 1.4.6版本更新：\n新增支持cdn_prefix的数组/函数/字符串传参方式，更灵活和强大\n新增支持内联嵌入CSS/JS到html。 只需要再url后面添加 ?_gm_inline\n完善内联资源嵌入后的自动更新引用文件(html和CSS)\n完善文档\n</code></pre><pre><code>gulpman 1.3.6版本更新：\n\n新增对React/jsx支持，可以直接写ReactJS了</code></pre><pre><code>gulpman 1.3.3版本更新：\n\n1、新增对复杂目录和多级目录设定支持:\n比如下面这种模板、静态文件复杂的、多级的路径：\ngulpman.config({\n&nbsp; &nbsp; 'components': 'components/cc',\n&nbsp; &nbsp; 'runtime_views': 'runtime_views/rv',\n&nbsp; &nbsp; 'dist_views': 'dist_views/dv/dv',\n&nbsp; &nbsp; 'runtime_assets': 'runtime_assets/ra/ra',\n&nbsp; &nbsp; 'dist_assets': 'dist_assets/da'\n&nbsp; &nbsp;&nbsp;\n})\n\n2、增加彩色log\n\n3、增加base64关联的资源文件的自动关联编译，比如跟这个base64图片有关的html、css都会自动编译(监视模式下)\n</code></pre><p><br></p><p><br></p><p>先来个大致的介绍：</p><ul><li>使用gulpman按照模块划分后，模块根目录可以是<code>./components</code>(默认，可配置)，如果你有个模块是foo，那么应该有如下目录：<code>./components/foo</code>，然后跟foo模块相关的<code>html|js|css|fonts|image</code>等资源文件都放到<code>foo</code>下，这个结构下，做开发时非常清晰、高效，便于模块组织、资源定位等。</li><li>通过<code>gm:publish</code>命令构建后，会自动生成模板<code>views</code>目录，和静态资源<code>assets</code>目录。</li></ul><p><span style=\"color: rgb(51, 51, 51);\"><br></span></p><p><span style=\"color: rgb(51, 51, 51);\"><br></span></p><p><span style=\"color: rgb(51, 51, 51);\">Github源码： <a href=\"https://github.com/xunuoi/gulpman\">https://github.com/xunuoi/gulpman</a></span></p><p><br></p><p><br></p><h3><a href=\"https://github.com/xunuoi/gulpman#introduction-说明\"></a>Introduction 说明</h3><ul><li>支持Mac、Linux环境下安装、使用</li><li>Windows环境未做测试，由于安装脚本使用到shell，windows不支持sh，可能需要手动安装gulp-sass等模块。</li></ul><h3><br></h3><h3><a href=\"https://github.com/xunuoi/gulpman#install-安装\"></a>Install 安装</h3><p>cd into your project dir and install:</p><pre><code class=\"lang-bash\">npm install gulpman --save-dev</code></pre><h3><br></h3><h3><a href=\"https://github.com/xunuoi/gulpman#usage-使用\"></a>Usage 使用说明</h3><h4><br></h4><h4><a href=\"https://github.com/xunuoi/gulpman#in-your-gulpfile\"></a>一、In Your gulpfile:</h4><p>只需要require gulpman模块，就会自动加载gm:publish、gm:develop（开发监视模式）等预置的task，使用时在命令行直接输入gulp gm:publish即可执行</p><p><br></p><pre><code class=\"lang-js\"><span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">/**</span>\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\"> * Gulpfile.js</span>\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\"> */</span>\n\n\n<span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">var</span> gulp <span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">=</span> <span class=\"pl-c1\" style=\"box-sizing: border-box; color: rgb(0, 134, 179);\">require</span>(<span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>gulp<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>),\n    gman <span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">=</span> <span class=\"pl-c1\" style=\"box-sizing: border-box; color: rgb(0, 134, 179);\">require</span>(<span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>gulpman<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>)\n\n\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// your other tasks ...你的其他task\n\n</span>\n\n\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// 设置路径、CDN、资源URL前缀等，API超级简单。\n// 你也可以不设置，全部采用默认值!</span>\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// if you want to set the dir, you can use config API:</span>\n\n<span class=\"pl-smi\" style=\"box-sizing: border-box;\">gman</span>.<span class=\"pl-en\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">config</span>({\n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// 是否使用绝对路径，默认true,推荐使用，方便服务器配置。比如`/static/home/main.js`这种风格。</span>\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// 如果is_absolute是false, 那么可能是`../../assets/static/home/main.js`这种风格。</span>\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// 具体取决于项目情况、服务端配置等。</span>\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// if set the assets url prefix as absolute or relative, default: true</span>\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>is_absolute<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-c1\" style=\"box-sizing: border-box; color: rgb(0, 134, 179);\">true</span>,\n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// cdn prefix 配置CDN</span>\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>cdn_prefix<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>, \n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// 配置资源URL前缀，建议 /xxx这种</span>\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// usually set as /static, this involves the server config ,such as the static path of nginx</span>\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>url_prefix<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>/static<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span> \n\n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// 模块COMPONENTS目录，同一个模块的html和资源文件在一起。默认 'components'即可</span>\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>components<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>components<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>,\n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// develop和publish下的views目录，跟服务端框架的views目录配置一致，比如express</span>\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>runtime_views<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>views<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>,\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>dist_views<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>views_dist<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>,\n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// develop和publish下的assets静态目录，跟服务器配置有关，比如nginx的static目录指向</span>\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>runtime_assets<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>assets<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>,\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>dist_assets<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>assets_dist<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>,\n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// 第三方JS类库、模块的目录，推荐设置为`lib`或`bower_components`（这样bower可以直接安装到这个目录）</span>\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// 这个目录默认打包时为全局模块目录，可以直接`require('xxx')`，而不用加相对路径</span>\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// the js library dir, set as a global module. Also you can set as bower_components</span>\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>lib<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>lib<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>, \n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// 可以添加一个自定的全局模块目录，该目录下的js模块，也作为全局模块来require，不需要相对路径。</span>\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// the global module dir</span>\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>global<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>common<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span> \n})\n\n</code></pre><h4><br></h4><h4><br></h4><h4>二、全局模块介绍：</h4><p><br></p><p>1. config的配置中，lib和global都是全局模块目录。举个例子说明：你的components/lib目录下有一个模块 foo.js，就是： components/lib/foo.js，那么你在你的es6文件中，就可以这样使用：` import foo from 'foo' `，不需要写成 ` import foo from '../lib/foo' `。&nbsp;</p><p>2. 同理global那个配置也是这样的，推荐将lib目录设置成跟bower一致的，全部来存放第三方类库，而global设置的目录，比如common，可以存放自己的 公用模块。</p><p>3. 这样开发会更加灵活、方便。注意全局模块不要用同名冲突。</p><p><br></p><h4><br></h4><h4><a href=\"https://github.com/xunuoi/gulpman#in-your-cli\"></a>三、In Your CLI 命令行中调用:</h4><p>就是普通的调用gulp 的task</p><pre><code class=\"lang-bash\"><span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\"># 初始化目录，建立components目录并添加一份html的demo文件</span>\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\"># init components dir and a html demo</span>\ngulp gm:init\n\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\"># publish 发布资源，包括合并、压缩资源、rev产生MD5等</span>\ngulp gm:publish\n\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\"># develop and watch 开发模式，监视相关文件变动，增量更新</span>\ngulp gm:develop\n\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\"># clean 清理构建输出的目录和文件</span>\ngulp gm:clean\n\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\"># 编译输出一份运行时资源文件，但是不进入监视状态</span>\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\"># compile for develop, not watch</span>\ngulp gm:compile\n</code></pre>","excerpt":"可以像FIS一样，具有模块化的前端目录结构。基于gulp，简单、灵活，容易扩展和修改，懂点gulp的童鞋都可以自己修改、使用、组合。不需要任何服务端的整合工作，这个与FIS有很大不同，不需要修改服务端代码来适配，就像正常的html一样，去引用你的js、css、img、fonts等资源，无侵入。整合SCSS ES6 Browserify|cssnano|uglify|imagmein|rev等前端常用套件，同时有监视文件变动功能(watch)，可配置的发布目录、资源目录、CDN等，方便开发，简单易用，一站式搞定。更新说明：gulpman 1.4.6版本更新","title":"Gulpan-简单灵活的模块化前端解决方案!","author":"Cloud","type":"tech","en_gallery":false,"enable":true,"tag":["前端"],"img":[],"thumb":[],"mid":[],"raw":[],"createdAt":"2016-01-23T10:11:15.235Z","updatedAt":"2016-02-05T08:19:47.223Z","pv_count":3662,"article_id":"56a351c3e48d2d05682aa0ac","id":"56a351c3e48d2d05682aa0ac"},{"content":"<p style=\"margin-left: 0px;\">Karat克拉这个网站，就是基于sails开发的，前后端都启用了es6+es7特性的开发。</p><p style=\"margin-left: 0px;\">我在github上传了部署代码和文档：<a href=\"https://github.com/xunuoi/sails-babel\">https://github.com/xunuoi/sails-babel</a>&nbsp;</p><p style=\"margin-left: 0px;\">修改变动比较多，github上可能不是最新的代码和文档。</p><p style=\"margin-left: 0px;\"><br></p><p style=\"margin-left: 0px;\">主要是用了一个支持babel的hook和babel的gulp组件，来支援es6~</p><p style=\"margin-left: 0px;\"><br></p><p style=\"margin-left: 0px;\">新建一个空sails项目，不包含前端：</p><pre><code class=\"lang-bash\">sails new withu.cc --no-frontend --template=swig</code></pre><p>修改.sailssrc</p><p>1、添加如下，否则启动sails lift会有找不到grunt的warn</p><pre><code>{\n  \"generators\": {\n    \"modules\": {}\n  },\n  \"hooks\": {\n    \"grunt\": false\n  },\n  \"paths\": {\n    \"views\": \"views\"\n  }\n\n}</code></pre><p>2、修改模板引擎配置<br></p><p>安装swig： 目录下，npm install swig</p><p>config/views文件：</p><pre><code>engine: {\n&nbsp; &nbsp; 'name': 'swig',\n&nbsp; &nbsp; 'ext': 'html',\n&nbsp; &nbsp; fn: function (pathName, locals, cb) {\n&nbsp; &nbsp; &nbsp; var swig = require('swig')\n&nbsp; &nbsp; &nbsp; swig.setDefaults({&nbsp;\n&nbsp; &nbsp; &nbsp; &nbsp; loader: swig.loaders.fs('./views')&nbsp;\n&nbsp; &nbsp; &nbsp; })\n&nbsp; &nbsp; &nbsp; return swig.renderFile(pathName, locals, cb);\n&nbsp; &nbsp; }\n&nbsp; },</code></pre><p>3、简历 views和assets目录</p><p>assets目录：&nbsp;</p><p>js</p><p>lib： for bower</p><p>img</p><p>font</p><p>css</p><p>&nbsp;scss 或者less</p><p>==================================</p><p>4、安装bower</p><p>assets目录下 bower init</p><p>assets下目录static</p><p>.bowerrc:</p><pre><code>{\n&nbsp; \"directory\": \"./static/lib/\",\n&nbsp; \"analytics\": false,\n&nbsp; \"timeout\": 120000\n}\n</code></pre><p>5、配置nginx静态目录和upstream</p><p>vhost&nbsp;</p><h2><span style=\"color: rgb(227, 55, 55);\">6、配置安装gulp来适配当前view模式</span></h2><p>assets目录下，设置bower和gulpfile.js</p><p>npm install安装时可能会有问题：</p><blockquote><p>Error: pngquant failed to build, make sure that libpng-dev is installed</p></blockquote><p>This error means that the system is lacking&nbsp;<code>libpng</code>&nbsp;development library, which is needed to install<code>imagemin</code>&nbsp;Node.JS module. To install it on CentOS 6, you need to issue this command:</p><pre><code>yum install libpng-devel</code></pre><p><br></p><p>另外简单介绍下assets/gulpfile.js中的babel配置，完整文件请戳到github上：&nbsp;<a href=\"https://github.com/xunuoi/sails-babel/blob/master/assets/gulpfile.js\" rel=\"nofollow\">https://github.com/xunuoi/sails-babel/blob/master/assets/gulpfile.js</a></p><p>通过配置来启用你想要的es6、7特性：</p><pre><code class=\"lang-js\">var babelOptional = [\n&nbsp; &nbsp; \"es7.asyncFunctions\",\n&nbsp; &nbsp; \"es7.objectRestSpread\",\n&nbsp; &nbsp; \"es7.functionBind\",\n&nbsp; &nbsp; \"es7.comprehensions\",\n]\n</code></pre><p>在gulp task中引用这个option：</p><pre><code class=\"lang-js\">gulp.task('es6', function() {\n&nbsp; return gulp.src([\n&nbsp; &nbsp; &nbsp; j(ASSETS_ROOT, 'es6/**/*.es6'),&nbsp;\n&nbsp; &nbsp; ])\n&nbsp; &nbsp; .pipe(p.babel({\n&nbsp; &nbsp; &nbsp; optional: babelOptional,\n&nbsp; &nbsp; }))\n&nbsp; &nbsp; .pipe(gulp.dest(\n&nbsp; &nbsp; &nbsp; j(ASSETS_ROOT, '.tmp')\n&nbsp; &nbsp; ))\n})</code></pre><p><br></p><p><br></p><p>==========================================================================</p><p>前端构建中，涉及到配合es6中的import 语句（相当于烂大街的require等）来打包构建（browserify来构建），并且增加md5防止缓存问题，需要对一个gulp插件修改一下，这个插件是gulp-md5-plus，但是本身不支持文件搜索定位，所以修改下来支持，详细如下：</p><p>修改gulp-md5-plus ，增加root选项</p><pre><code>module.exports = function (size, ifile, rootpath) {\nsize = size | 0;\nrootpath = rootpath || '\nxxx\n})</code></pre><pre><code>&nbsp; &nbsp; &nbsp; &nbsp; var match_file_path = path.join(rootpath, relativepath)\n&nbsp; &nbsp; &nbsp; &nbsp; var md5_filename = filename.split('.').map(function(item, i, arr){\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return i == arr.length-2 ? item + '_'+ d : item;\n&nbsp; &nbsp; &nbsp; &nbsp; }).join('.');\n&nbsp; &nbsp; &nbsp; &nbsp; var relative_dir = path.relative(file.base, dir)\n&nbsp; &nbsp; &nbsp; &nbsp; var md5_file_path = path.join(rootpath,relative_dir, md5_filename)\n&nbsp; &nbsp; &nbsp; &nbsp; console.log('debug: gulp-md5-plus: \\n', md5_file_path)\n&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;\n</code></pre><p>然后替换replace：</p><pre><code>replace(new RegExp(match_file_path), md5_file_path);</code></pre><p><br></p><p>修改后的完整代码（安装完gulp-md5-plus，他的目录下index.js的代码）：</p><p><br></p><pre><code>var path = require('path')\n, gutil = require('gulp-util')\n, through = require('through2')\n, crypto = require('crypto')\n, fs = require('fs')\n, glob = require('glob');\nmodule.exports = function (size, ifile, rootpath) {\n&nbsp; &nbsp; size = size | 0;\n&nbsp; &nbsp; rootpath = rootpath || ''\n&nbsp; &nbsp; return through.obj(function (file, enc, cb) {\n&nbsp; &nbsp; &nbsp; &nbsp; if (file.isStream()) {\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.emit('error', new gutil.PluginError('gulp-debug', 'Streaming not supported'));\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return cb();\n&nbsp; &nbsp; &nbsp; &nbsp; }\n&nbsp; &nbsp; &nbsp; &nbsp; if(!file.contents){\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return cb();\n&nbsp; &nbsp; &nbsp; &nbsp; }\n&nbsp; &nbsp; &nbsp; &nbsp; var d = calcMd5(file, size)\n&nbsp; &nbsp; &nbsp; &nbsp; , filename = path.basename(file.path)\n&nbsp; &nbsp; &nbsp; &nbsp; , relativepath = path.relative(file.base ,file.path)\n&nbsp; &nbsp; &nbsp; &nbsp; , sub_namepath = relativepath\n&nbsp; &nbsp; &nbsp; &nbsp; .replace(new RegExp(filename) , \"\").split(path.sep).join('/')\n&nbsp; &nbsp; &nbsp; &nbsp; , dir;\n&nbsp; &nbsp; &nbsp; &nbsp; if(file.path[0] == '.'){\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dir = path.join(file.base, file.path);\n&nbsp; &nbsp; &nbsp; &nbsp; } else {\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dir = file.path;\n&nbsp; &nbsp; &nbsp; &nbsp; }\n&nbsp; &nbsp; &nbsp; &nbsp; dir = path.dirname(dir);\n&nbsp; &nbsp; &nbsp; &nbsp; var match_file_path = path.join(rootpath, relativepath)\n&nbsp; &nbsp; &nbsp; &nbsp; var md5_filename = filename.split('.').map(function(item, i, arr){\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return i == arr.length-2 ? item + '_'+ d : item;\n&nbsp; &nbsp; &nbsp; &nbsp; }).join('.');\n&nbsp; &nbsp; &nbsp; &nbsp; var relative_dir = path.relative(file.base, dir)\n&nbsp; &nbsp; &nbsp; &nbsp; var md5_file_path = path.join(rootpath,relative_dir, md5_filename)\n&nbsp; &nbsp; &nbsp; &nbsp; console.log('debug: gulp-md5-plus: \\n', match_file_path)\n&nbsp; &nbsp; &nbsp; &nbsp; console.log('debug: gulp-md5-plus: \\n', md5_file_path)\n&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;\n&nbsp; &nbsp; &nbsp; &nbsp; if(Object.prototype.toString.call(ifile) == \"[object Array]\"){\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ifile.forEach(function(i_ifile){\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; i_ifile &amp;&amp; glob(i_ifile,function(err, i_files){\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(err) return console.log(err);\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; i_files.forEach(function(i_ilist){\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var result = fs.readFileSync(i_ilist,'utf8').replace(new RegExp(match_file_path), md5_file_path);\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fs.writeFileSync(i_ilist, result, 'utf8');\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; })\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; })\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; })\n&nbsp; &nbsp; &nbsp; &nbsp; }else{\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ifile &amp;&amp; glob(ifile,function(err, files){\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(err) return console.log(err);\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; files.forEach(function(ilist){\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var result = fs.readFileSync(ilist,'utf8').replace(new RegExp(match_file_path), md5_file_path);\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fs.writeFileSync(ilist, result, 'utf8');\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; })\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; })\n&nbsp; &nbsp; &nbsp; &nbsp; }\n&nbsp; &nbsp; &nbsp; &nbsp; file.path = path.join(dir, md5_filename);\n&nbsp; &nbsp; &nbsp; &nbsp; this.push(file);\n&nbsp; &nbsp; &nbsp; &nbsp; cb();\n&nbsp; &nbsp; }, function (cb) {\n&nbsp; &nbsp; &nbsp; &nbsp; cb();\n&nbsp; &nbsp; });\n};\nfunction calcMd5(file, slice){\n&nbsp; &nbsp; var md5 = crypto.createHash('md5');\n&nbsp; &nbsp; md5.update(file.contents, 'utf8');\n&nbsp; &nbsp; return slice &gt;0 ? md5.digest('hex').slice(0, slice) : md5.digest('hex');\n}\n</code></pre><p><br></p><p>==========================================================================</p><p><br></p><p>关于 gulpfile.js</p><p>两个gulpfile。assets和根目录下各一个</p><p>browserify只能打包js，也就是转化成es5的js文件。通过添加paths这个函数，可以设置全局模块的路径，注意此时paths必须是转成js的模块，不是es6的路径。</p><p>部分打包代码：</p><pre><code>function browserifyOne(fpath){\n    return browserify({\n          entries: fpath,\n          debug: true,\n          sourceMaps: false,\n          extensions: ['.es6', '.jsx', '.js'],\n          paths: [\n            j(ASSETS_ROOT, 'lib'),\n            j(ASSETS_ROOT, '.tmp/common')\n          ]\n      })\n      /*.transform(babelify.configure({\n        optional: babelOptional\n      }))*/\n      /*.require(require.resolve('babel/polyfill'),{expose: 'babel/polyfill'} )*/ // use regenerators\n      .bundle()\n      .pipe(source(fpath))\n      .pipe(buffer())\n      .pipe(p.rename(function(path) {\n        path['dirname'] = path['dirname'].replace('.tmp', 'js').replace(j(ASSETS_ROOT,'/'), '')\n      }))\n      /*.on('error', function(err){\n        throw Error(err)\n      })*/\n}<br></code></pre><h2><span style=\"color: rgb(227, 55, 55);\">7、sails服务端启用es6</span></h2><p>安装sails-babel-hook的钩子，自动调用babel转化，不需要再手工写gulp来转了</p><p>8、配置js和lib</p><p>让jquery能打包进入js中正常使用</p><pre><code>//main.js\n\nimport 'jquery/dist/jquery'\n$('body').html('i am jquery googog')\nexport { foo, bar }</code></pre><p>修改jquery源代码</p><pre><code>(function( global, factory ) {\n\tif (false &amp;&amp; typeof module === \"object\" &amp;&amp; typeof module.exports === \"object\" ) {</code></pre><p>9、适配mongodb</p><p>npm install --save-dev sails-mongo</p><p>创建对应model</p>","excerpt":"Karat克拉这个网站，就是基于sails开发的，前后端都启用了es6+es7特性的开发。我在github上传了部署代码和文档：https://github.com/xunuoi/sails-babel 修改变动比较多，github上可能不是最新的代码和文档。主要是用了一个支持babel的hook和babel的gulp组件，来支援es6~新建一个空sails项目，不包含前端：sails new withu.cc --no-frontend --template=swig修改.sailssrc1、添加如下，否则启动sails lift会有找不到grunt的","img":[],"title":"全栈es6、7的js开发－基于Sails","author":"Cloud","type":"tech","en_gallery":false,"enable":true,"tag":["前端","Web","Sails","Express"],"thumb":[],"mid":[],"createdAt":"2015-10-27T12:34:27.378Z","updatedAt":"2015-11-18T10:04:36.053Z","pv_count":3589,"article_id":"562f6f53d6db69011de1bbe0","id":"562f6f53d6db69011de1bbe0"},{"content":"<p>什么Ajax、Pjax、Njax。。。神马玩意？ 有Njax吗？ 木有。。。不过真有Pjax！！</p><p>其实pjax就是用到了html5的新history api： pushState和replaceState。<b>如果浏览器不支持，会自动降级为普通http访问，跟正常a链接一样</b></p><p><span style=\"color: rgb(51, 51, 51);\">具体啥区别？</span>先视觉通感感受下！！上图：</p><p><br></p><p>1、普通的http切换页面的请求方式，闪烁、白屏、卡顿、加载等，就是完整加载一坨页面嘛<img src=\"/static/lib/simditor-emoji/images/emoji/joy.png\" width=\"20\" height=\"20\" alt=\"joy\" data-emoji=\"true\" data-non-image=\"true\">，又慢又挫的，就像如花姑娘：</p><p><img alt=\"1.jpg\" src=\"/img/large/559038a7-2d21-4123-a03c-f1a3970a56ff.jpg\" width=\"500\" height=\"248\"><br></p><p><br></p><p>2、通过Ajax来开发页面，只加在部分数据，没有切换和闪烁，清新宜人哦，就像街上MM、邻家小妹<img src=\"/static/lib/simditor-emoji/images/emoji/stuck_out_tongue_winking_eye.png\" width=\"20\" height=\"20\" alt=\"stuck_out_tongue_winking_eye\" data-emoji=\"true\" data-non-image=\"true\"></p><p>如果只是ajax的话，不能保存页面状态！一刷新就没了啊！！转瞬即逝啊！！</p><p>街上的MM都走远了，童鞋别看了，找不到了！！</p><p>如果要保存的话，结合hash#，其实很坑爹啊！</p><p>很多时候引入hash,导致开发复杂不说，关键是影响SEO，百度不认识 #! 啊 只有谷歌认识有毛线用啊被墙了!<img src=\"/static/lib/simditor-emoji/images/emoji/sob.png\" width=\"20\" height=\"20\" alt=\"sob\" data-emoji=\"true\" data-non-image=\"true\"></p><p><img alt=\"2.JPG\" src=\"/img/large/031ecc7d-3564-4884-abfa-bbfea938d786.JPG\" width=\"400\" height=\"600\"><br></p><p><br></p><p>3、Pjax来了啊，喜大普奔！既能无切换、高性能加载显示html，又能跟普通url兼容，前后端开发逻辑也简单！</p><p>就像下面的女神吉田沙世和摄影模特啊！关键是你还能抱回家，轻松hold住，各种调戏啊！卧槽。。说漏嘴了。。咳说正事！</p><p><img alt=\"3.jpg\" src=\"/img/large/2394c653-c8dc-43d9-9861-5e9be3035e2d.jpg\" width=\"480\" height=\"319.6363636363636\"><br></p><p><img alt=\"4.jpg\" src=\"/img/large/091ea772-e6c9-41c7-8740-883003bf1253.jpg\" width=\"480\" height=\"312.8\"><br></p><p><br></p><p><br></p><p>说完了视觉上的通感感受，我们再看一眼开发的区别，是不是开发很麻烦啊 ！！！上代码:</p><p><br></p><pre><code>MO.go('.ctn a', '#ttt')</code></pre><p>然后呢？&nbsp;</p><p>木有了啊！只要后台再根据请求头区分下是否是pjax来返回片段html代码就可以了！</p><p>浏览器不支持pjax怎么办？ 自动将极为普通http啊！！不用担心的！</p><p>艾玛、这么happy！真幸福！</p><p>简直就是修炼<b>玉女心经</b>的节奏啊！ 耶，操练起来！</p><p><br></p><p><br></p><h2><a href=\"https://github.com/xunuoi/MO.Pjax/blob/master/README.md#usage\"></a>\b玉女心经使用指南:</h2><h4><br></h4><h4><a href=\"https://github.com/xunuoi/MO.Pjax/blob/master/README.md#install\"></a>\b安装:</h4><blockquote><ol><li>首先需要jQuery这个基础库~其实可以用纯js写这个pjax类库的，但是，我懒。。。</li><li>引入编译es5后到dist目录下的 <b>mo.pjax.es5.js </b>脚本文件到html文件，如果使用es6，请import并配置编译</li></ol></blockquote><pre><code class=\"lang-js\"><span class=\"pl-e\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">src</span>=<span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">\"</span>./dist/mo.pjax.es5.js<span class=\"pl-pds\" style=\"box-sizing: border-box;\">\"</span></span></code></pre><p><b>可以去github上下载：&nbsp;<a href=\"https://github.com/xunuoi/MO.Pjax\">https://github.com/xunuoi/MO.Pjax</a></b></p><p><span style=\"color: rgb(0, 0, 0);\"><br></span></p><p><span style=\"color: rgb(0, 0, 0);\"><br></span></p><p><span style=\"color: rgb(0, 0, 0);\"><b>用法:</b></span></p><p><br></p><p>Api Params Desc 参数注释:</p><p><br></p><blockquote><p><b><i>_fetch : &nbsp;</i></b> 是否请求网络，比如这次pjax的url参数是/about ,如果_fetch为false，那么不发送http 请求或读取缓存，只执行回调。</p><p>多用在复杂web/app设计中，比如当前内容已存在于html中，不想更新和获取.</p><p>* MO.state默认值是false，因为只是重新定义本页面状态，不需要更新已有数据和HTML&nbsp;</p><p>* MO.touch中默认值是true，因为要从http或缓存中 更新数据、html</p></blockquote><p><br></p><blockquote><p><b>_fire：</b>是否立刻触发onpopfn ，立刻执行回调函数。false表示popstate 事件触发后才执行</p><p>* MO.state中默认值是false, 只有popstate事件触发后才执行</p><p><span style=\"color: rgb(51, 51, 51);\">* MO.go中调用了MO.state，并传参_fire值为false.</span><br></p><p>* MO.define中调用了MO.state，并传参_fire值为true.</p></blockquote><h4><br></h4><h4><br></h4><h4><b>配置:</b><br></h4><p>调教一下，再美的女神也不是天生就符合你的口味，来这定制下啊！</p><pre><code><span class=\"pl-smi\" style=\"box-sizing: border-box;\">MO</span>.<span class=\"pl-en\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">config</span>({\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>type<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>POST<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>,\n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// this can be used for you back-end ,to detect if it is a pjax request</span>\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>pjaxHeader<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> {\n        <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>X-Http-Pjax<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>Pjax<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>\n    }\n})</code></pre><p><br></p><p>详细配置和注解:</p><pre><code class=\"lang-js\">{\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>type<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>POST<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>,<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// post is default http请求方式</span>\n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// if cache data， 是否缓存</span>\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>cache<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-c1\" style=\"box-sizing: border-box; color: rgb(0, 134, 179);\">true</span>,\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// 'cacheExpires': 10000, // 0 means always avaliable, default none 缓存时间</span>\n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// if store data in localStorage , default true </span>\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>storage<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-c1\" style=\"box-sizing: border-box; color: rgb(0, 134, 179);\">true</span>, <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">//是否启用localStorage</span>\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">//如果storageExpires设置为0或false，永不过期</span>\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>storageExpires<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-c1\" style=\"box-sizing: border-box; color: rgb(0, 134, 179);\">43200000</span>, <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// 12 hours ,default 12 </span>\n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// the res data type, default html</span>\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>dataType<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>html<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>, <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">//返回数据类型，默认html</span>\n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// you can set your own header ,just use `pjaxHeader` opts, </span>\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// which you can detect if it is an pjax request in back-end </span>\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// 你可以自己定义请求头，方便后端判断是否是pjax请求，如果是pjax, 返回部分html， fragment</span>\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>pjaxHeader<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> {\n        <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>Http-Request-Pjax<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>Fragment<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>\n    },\n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// you can set the fn which will triggered before MO.touch and popstate event happened</span>\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// 触发pjax操作前和 出现popstate的事件时的事件函数, 参数是state，包含url、title等信息</span>\n    <span class=\"pl-en\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">before</span> (<span class=\"pl-smi\" style=\"box-sizing: border-box;\">state</span>) { ... } <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">//默认无</span>\n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// you can set the beforeSend fn , before ajax request send.</span>\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// jquery的ajax方法调用，请求前设置请求头，可以覆盖</span>\n    <span class=\"pl-en\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">beforeSend</span> (<span class=\"pl-smi\" style=\"box-sizing: border-box;\">req</span>){\n        <span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">let</span> ph <span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">=</span> <span class=\"pl-v\" style=\"box-sizing: border-box; color: rgb(237, 106, 67);\">this</span>[<span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>pjaxHeader<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>]\n        <span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">for</span> (<span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">let</span> h <span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">in</span> ph ){\n            <span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">let</span> v <span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">=</span> ph[h]\n            <span class=\"pl-smi\" style=\"box-sizing: border-box;\">req</span>.<span class=\"pl-c1\" style=\"box-sizing: border-box; color: rgb(0, 134, 179);\">setRequestHeader</span>(h, v)\n        }\n    }\n}</code></pre><h4><b><br></b></h4><h4><b><br></b></h4><h4><b>Api说明:</b><br></h4><p>看看美女哪里长得最漂亮啊<img src=\"/static/lib/simditor-emoji/images/emoji/heart_eyes.png\" width=\"20\" height=\"20\" alt=\"heart_eyes\" data-emoji=\"true\" data-non-image=\"true\"><img src=\"/static/lib/simditor-emoji/images/emoji/heart_eyes.png\" width=\"20\" height=\"20\" alt=\"heart_eyes\" data-emoji=\"true\" data-non-image=\"true\"></p><p><br></p><p>一、MO.go 最简单！</p><pre><code class=\"lang-js\">MO.go(aSelector, ctnSelector, onSuccess)</code></pre><p>这个是最简单和常用的api， 只需要go一下，传入2个参数即可，一个是点击后触发pjax的元素选择器，一般是a，第二个是更新返回内容的html 。第三个是回调函数，可选。</p><p><br></p><p></p><p>MO.go添加处理错误的函数，比如出现网络请求错误，比如404，会在此处捕获</p><pre><code class=\"lang-js\"><span class=\"pl-smi\" style=\"box-sizing: border-box;\">MO</span>.<span class=\"pl-c1\" style=\"box-sizing: border-box; color: rgb(0, 134, 179);\">go</span>(<span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>.ctn a<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>, <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>#ttt<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>, \n<span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">function</span> <span class=\"pl-en\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">onSuccess</span>(<span class=\"pl-smi\" style=\"box-sizing: border-box;\">res</span>, <span class=\"pl-smi\" style=\"box-sizing: border-box;\">$aEle</span>){\n    <span class=\"pl-en\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">console</span>.<span class=\"pl-c1\" style=\"box-sizing: border-box; color: rgb(0, 134, 179);\">log</span>(res, $aEle)\n}, \n<span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">function</span> <span class=\"pl-en\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">onError</span>(<span class=\"pl-smi\" style=\"box-sizing: border-box;\">err</span>, <span class=\"pl-smi\" style=\"box-sizing: border-box;\">$aEle</span>){\n    <span class=\"pl-en\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">console</span>.<span class=\"pl-c1\" style=\"box-sizing: border-box; color: rgb(0, 134, 179);\">log</span>(err, $aEle)\n})</code></pre><p><br></p><p><span style=\"color: rgb(51, 51, 51);\">二、MO.define 不常用</span><br></p><p>定义当前页面的state状态，不常用</p><pre><code class=\"lang-js\">MO.define(ctn, htmlData)</code></pre><p></p><p><br></p><p>三、MO.state 适合复杂开发</p><p>* <span style=\"color: rgb(51, 51, 51);\">MO.state和MO.go</span>两者经常配合使用，比较灵活</p><blockquote><p>详细定义当前页面state状态，以及是否请求次url, 和是否立刻触发onpopFn_fire<br></p><p></p></blockquote><pre><code class=\"lang-js\">MO.state(url, title, onpopFn, _data=null, _fetch=false, _fire=false)\n</code></pre><p><br></p><p>四、<span style=\"color: rgb(51, 51, 51);\">MO.go 复杂开发，很好用啊！！！</span></p><p>做复杂交互和逻辑时，比较常用</p><blockquote><p>* 更强大和灵活的使用pjax， 可以定义 pjax的操作的url、回调、是否发起此url的网络请求等，同样可以添加fail的错误处理函数</p></blockquote><p></p><pre><code class=\"lang-js\">MO.touch(apiUrl, title, onpopFn, _fetch=true)</code></pre><p></p><p>给touch添加fail处理网络请求错误，添加方式如下<br></p><pre><code class=\"lang-js\"><span class=\"pl-smi\" style=\"box-sizing: border-box;\">MO</span>.<span class=\"pl-en\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">touch</span>(apiUrl, title, onpopFn, _fetch<span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">=</span><span class=\"pl-c1\" style=\"box-sizing: border-box; color: rgb(0, 134, 179);\">true</span>)\n.<span class=\"pl-en\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">fail</span>(<span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">function</span>(<span class=\"pl-smi\" style=\"box-sizing: border-box;\">err</span>) {\n    <span class=\"pl-en\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">console</span>.<span class=\"pl-c1\" style=\"box-sizing: border-box; color: rgb(0, 134, 179);\">log</span>(<span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>There is an error <span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>, err)\n})\n</code></pre><p><br></p><p><br></p><p><br></p><p><b>服务端处理：</b></p><blockquote><p>服务端只需要判断是普通请求(完整html)还是pjax请求（fragment html）</p><p>可以通过MO.config({'pjaxHeader': {xxx: yyy}})来设置请求头，或者修改type为POST\\GET等，只要让服务端能判断即可！</p></blockquote><p><br></p><p><br></p><p><b>说明：</b></p><blockquote><ul><li>通过MO.touch和MO.state，可以做非常复杂的pjax 应用，自定义事件\\UI等</li><li>如果要简单使用，就是直接 MO.go(), 传入你想要pjax的a元素的selector即可</li><li>配合启用cache/localStorage(默认都启用), 给用户更好操作体验，减少等待、卡顿</li></ul></blockquote><p><br></p><p><br></p><p><br></p><p><br></p><p><b>本地存储：store/removeStore</b></p><p>原来还有这么个福利！！！</p><p>可以在引入MO.Pjax的任何页面，来store数据，当其他页面pjax到此页面的时候，数据直接从storage获取就可以啦！这个在做多重请求方式的web开发时，经常用到哦！</p><p><br></p><blockquote><ul><li>提供本地存储和自动过期机制，</li><li>过期时间通过MO.config({'storageExpires': xxx})来设定</li><li>自动创建一个item来跟踪这条数据的时间: &nbsp;{ k+'createdAt': (new Date).getTime() },</li></ul></blockquote><p><br></p><p><b>Store的Api</b></p><p></p><pre><code><span class=\"pl-smi\" style=\"box-sizing: border-box;\">\nMO</span>.<span class=\"pl-en\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">store</span>(k, v)\n<span class=\"pl-smi\" style=\"box-sizing: border-box;\">MO</span>.<span class=\"pl-en\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">removeStore</span>(k, v)</code></pre><h4><br></h4><h4><br></h4><h4><br></h4><h4><br></h4><h4><b>MO.pjax 使用 MO.go 举例</b></h4><h4>女神跳个舞吧！！<br></h4><p><a href=\"https://github.com/xunuoi/MO.Pjax/blob/master/README.md#html\"></a>html代码</p><pre><code><span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\"><!-- Index.html 这个是index.html文件 --></span>\n\n&lt;<span class=\"pl-ent\" style=\"box-sizing: border-box; color: rgb(99, 163, 92);\">div</span> <span class=\"pl-e\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">class</span>=<span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">\"</span>ctn<span class=\"pl-pds\" style=\"box-sizing: border-box;\">\"</span></span>&gt;\n    &lt;<span class=\"pl-ent\" style=\"box-sizing: border-box; color: rgb(99, 163, 92);\">h3</span>&gt;Test Mo.pjax<!--<span class=\"pl-ent\" style=\"box-sizing: border-box; color: rgb(99, 163, 92);\"-->h3&gt;\n    &lt;<span class=\"pl-ent\" style=\"box-sizing: border-box; color: rgb(99, 163, 92);\">p</span>&gt;\n       &lt;<span class=\"pl-ent\" style=\"box-sizing: border-box; color: rgb(99, 163, 92);\">a</span> <span class=\"pl-e\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">href</span>=<span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">\"</span>/about.html<span class=\"pl-pds\" style=\"box-sizing: border-box;\">\"</span></span>&gt;About<!--<span class=\"pl-ent\" style=\"box-sizing: border-box; color: rgb(99, 163, 92);\"-->a&gt;\n        &lt;<span class=\"pl-ent\" style=\"box-sizing: border-box; color: rgb(99, 163, 92);\">a</span> <span class=\"pl-e\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">href</span>=<span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">\"</span>/toxic.html<span class=\"pl-pds\" style=\"box-sizing: border-box;\">\"</span></span>&gt;Toxic<!--<span class=\"pl-ent\" style=\"box-sizing: border-box; color: rgb(99, 163, 92);\"-->a&gt; \n    <!--<span class=\"pl-ent\" style=\"box-sizing: border-box; color: rgb(99, 163, 92);\"-->p&gt;\n<!--<span class=\"pl-ent\" style=\"box-sizing: border-box; color: rgb(99, 163, 92);\"-->div&gt;\n&lt;<span class=\"pl-ent\" style=\"box-sizing: border-box; color: rgb(99, 163, 92);\">div</span> <span class=\"pl-e\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">id</span>=<span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">\"</span>ttt<span class=\"pl-pds\" style=\"box-sizing: border-box;\">\"</span></span> <span class=\"pl-e\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">style</span>=<span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">\"</span>margin-top: 30px;<span class=\"pl-pds\" style=\"box-sizing: border-box;\">\"</span></span>&gt;\n    &lt;<span class=\"pl-ent\" style=\"box-sizing: border-box; color: rgb(99, 163, 92);\">p</span>&gt;This is index html<!--<span class=\"pl-ent\" style=\"box-sizing: border-box; color: rgb(99, 163, 92);\"-->p&gt;\n<!--<span class=\"pl-ent\" style=\"box-sizing: border-box; color: rgb(99, 163, 92);\"-->div&gt;\n\n\n\n------------------------------------------------------------------\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\"><!-- about.html  这个是about.html文件 --></span>\n\n&lt;<span class=\"pl-ent\" style=\"box-sizing: border-box; color: rgb(99, 163, 92);\">div</span>&gt;This is about html<!--<span class=\"pl-ent\" style=\"box-sizing: border-box; color: rgb(99, 163, 92);\"-->div&gt;\n\n\n\n------------------------------------------------------------------\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\"><!-- toxic.html  这个是toxic.html文件  --></span>\n\n&lt;<span class=\"pl-ent\" style=\"box-sizing: border-box; color: rgb(99, 163, 92);\">div</span>&gt;This is toxic html<!--<span class=\"pl-ent\" style=\"box-sizing: border-box; color: rgb(99, 163, 92);\"-->div&gt;\n</code></pre><p><br></p><p><a href=\"https://github.com/xunuoi/MO.Pjax/blob/master/README.md#js-代码\"></a>JS 代码</p><pre><code class=\"lang-js\">MO.go('.ctn a', '#ttt')</code></pre><p></p><p><br></p><p><br></p><p><b>So easy! 搞定收工！</b></p><p>就似这么简单！就似这么任性！</p><p>我娘再也不用担心我无刷新更新页面内容了！Pjax大法\b好！</p><p>赶紧把pjax女神抱回家！！！<img src=\"/static/lib/simditor-emoji/images/emoji/heart_eyes.png\" width=\"20\" height=\"20\" alt=\"heart_eyes\" data-emoji=\"true\" data-non-image=\"true\"><img src=\"/static/lib/simditor-emoji/images/emoji/smile.png\" width=\"20\" height=\"20\" alt=\"smile\" data-emoji=\"true\" data-non-image=\"true\"></p>","excerpt":"什么Ajax、Pjax、Njax。。。神马玩意？ 有Njax吗？ 木有。。。不过真有Pjax！！其实pjax就是用到了html5的新history api： pushState和replaceState。如果浏览器不支持，会自动降级为普通http访问，跟正常a链接一样具体啥区别？先视觉通感感受下！！上图：1、普通的http切换页面的请求方式，闪烁、白屏、卡顿、加载等，就是完整加载一坨页面嘛，又慢又挫的，就像如花姑娘：2、通过Ajax来开发页面，只加在部分数据，没有切换和闪烁，清新宜人哦，就像街上MM、邻家小妹如果只是ajax的话，不能保存页面状态！一刷新","title":"Pjax 无刷新开发web，更好用户体验","author":"Cloud","type":"tech","en_gallery":true,"enable":true,"tag":["前端","Web","html5"],"img":["/img/large/559038a7-2d21-4123-a03c-f1a3970a56ff.jpg","/img/large/031ecc7d-3564-4884-abfa-bbfea938d786.JPG","/img/large/2394c653-c8dc-43d9-9861-5e9be3035e2d.jpg","/img/large/091ea772-e6c9-41c7-8740-883003bf1253.jpg"],"thumb":["/img/thumb/559038a7-2d21-4123-a03c-f1a3970a56ff.jpg","/img/thumb/031ecc7d-3564-4884-abfa-bbfea938d786.JPG","/img/thumb/2394c653-c8dc-43d9-9861-5e9be3035e2d.jpg","/img/thumb/091ea772-e6c9-41c7-8740-883003bf1253.jpg"],"mid":["/img/mid/559038a7-2d21-4123-a03c-f1a3970a56ff.jpg","/img/mid/031ecc7d-3564-4884-abfa-bbfea938d786.JPG","/img/mid/2394c653-c8dc-43d9-9861-5e9be3035e2d.jpg","/img/mid/091ea772-e6c9-41c7-8740-883003bf1253.jpg"],"raw":["/img/559038a7-2d21-4123-a03c-f1a3970a56ff.jpg","/img/031ecc7d-3564-4884-abfa-bbfea938d786.JPG","/img/2394c653-c8dc-43d9-9861-5e9be3035e2d.jpg","/img/091ea772-e6c9-41c7-8740-883003bf1253.jpg"],"createdAt":"2015-11-25T13:51:24.441Z","updatedAt":"2015-12-15T11:14:19.629Z","article_id":"5655bcdce6fecb6c65eded27","pv_count":3124,"id":"5655bcdce6fecb6c65eded27"},{"content":"<p style=\"margin-left: 0px;\">SVG动画，结合了CSS3的transition， 先看下效果图&nbsp;<img alt=\"屏幕快照 2015-10-27 下午8.25.00.png\" src=\"/img/081b72c0-8ffa-429a-a643-fa44adc6d3a3.png\" width=\"134\" height=\"51\"><br></p><p style=\"margin-left: 0px;\">动画效果： 直接参见本页面的导航菜单<img src=\"http://karat.cc/static/lib/simditor-emoji/images/emoji/laughing.png\" width=\"20\" height=\"20\" alt=\"laughing\" data-emoji=\"true\" data-non-image=\"true\"></p><p style=\"margin-left: 0px;\"><br></p><p style=\"margin-left: 0px;\">鼠标一上去，会有border变长，通过border的dashoffset的变化，包围住整个菜单矩形。</p><p style=\"margin-left: 0px;\">用到了css3的animation，详细用法大家可以看下：&nbsp;<a href=\"http://www.ruanyifeng.com/blog/2014/02/css_transition_and_animation.html\">http://www.ruanyifeng.com/blog/2014/02/css_transition_and_animation.html</a> 讲的比较好</p><p style=\"margin-left: 0px;\"><br></p><p style=\"margin-left: 0px;\">注意，Firefox中跟webkit计算dash-offset方法有不同，需要fix一下：</p><pre><code class=\"lang-css\">/**\n&nbsp;* FIX Firefox bugs: anti-direcion，\n&nbsp;* and dashoffset is different with Chrome\n&nbsp;*/\n@keyframes moz_draw {\n&nbsp; 0% {\n&nbsp; &nbsp; stroke-dasharray: $dash_len $dash_space_len;\n&nbsp; &nbsp; stroke-dashoffset: $dash_offset;\n&nbsp; &nbsp; stroke-width: $stroke_max_width;\n&nbsp; }\n&nbsp; 100% {\n&nbsp; &nbsp; stroke-dasharray: $dash_full_len+$dash_space_len;\n&nbsp; &nbsp; stroke-dashoffset: -$dash_offset;\n&nbsp; &nbsp; stroke-width: $stroke_min_width;\n&nbsp; }\n}\n</code></pre><p style=\"margin-left: 0px;\"><br></p><p style=\"margin-left: 0px;\">然后单独对Firefox进行CSS Hack：</p><pre><code class=\"lang-css\">&amp;:hover .shape {\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -webkit-animation: 0.5s linear 0s normal forwards 1 draw;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; animation: 0.5s linear 0s normal forwards 1 draw;\n\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //fix Firefox :stroke-dashoffset not 0 ??\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; @-moz-document url-prefix() {\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; animation: 0.5s linear 0s normal forwards 1 moz_draw;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }\n}</code></pre><p style=\"margin-left: 0px;\"><br></p><p style=\"margin-left: 0px;\">Firefox的差异，稍后有时间我再研究下。这种东西比较坑爹~</p><p style=\"margin-left: 0px;\"><br></p><p style=\"margin-left: 0px;\"><br></p><p style=\"margin-left: 0px;\">其他不多说，上代码，算法代码总有注释：</p><p style=\"margin-left: 0px;\">1. &nbsp;先上html结构参考：</p><p style=\"margin-left: 0px;\"><br></p><pre><code class=\"lang-html\">&lt;header&gt;\n&nbsp; &nbsp; &lt;nav&gt;\n&nbsp; &nbsp; &nbsp; &nbsp; &lt;div class=\"menu active\"&gt;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" width=\"180px\" height=\"48px\"&gt;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;rect width=\"180px\" height=\"48px\" class=\"shape\"&gt;&lt;/rect&gt;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;/svg&gt;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;a href=\"/\" class=\"text\"&gt;HOME&lt;/a&gt;\n&nbsp; &nbsp; &nbsp; &nbsp; &lt;/div&gt;\n&nbsp; &nbsp; &nbsp; &nbsp; &lt;div class=\"menu\"&gt;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" width=\"180px\" height=\"48px\"&gt;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;rect width=\"180px\" height=\"48px\" class=\"shape\"&gt;&lt;/rect&gt;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;/svg&gt;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;a href=\"/toxic\" class=\"text\"&gt;TOXIC&lt;/a&gt;&nbsp;\n&nbsp; &nbsp; &nbsp; &nbsp; &lt;/div&gt;\n&nbsp; &nbsp; &nbsp; &nbsp; &lt;div class=\"menu\"&gt;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" width=\"180px\" height=\"48px\"&gt;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;rect width=\"180px\" height=\"48px\" class=\"shape\"&gt;&lt;/rect&gt;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;/svg&gt;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;a href=\"/gallery\" class=\"text\"&gt;GALLERY&lt;/a&gt;\n&nbsp; &nbsp; &nbsp; &nbsp; &lt;/div&gt;\n&nbsp; &nbsp; &lt;/nav&gt;\n&lt;/header&gt;</code></pre><p style=\"margin-left: 0px;\"><br></p><p style=\"margin-left: 0px;\"><br></p><p style=\"margin-left: 0px;\">2. 这块是定义变量和动画， \b注意下stroke和dash、dash offset的值的定义：</p><pre><code class=\"lang-css\">@import 'define';\n@import 'util';\n\n/**\n&nbsp;* Stroke Calculator =====================\n&nbsp;* @type {[type]}\n&nbsp;* @description: stroke-dashoffset ,\n&nbsp;* 是起点偏移量，在svg的rect中，从左上角开始，\n&nbsp;* 如果offset为负值，那么线段向右偏移移动。\n&nbsp;* dasharray第一个是线段长度，\n&nbsp;* 第二个是空白间隔长度，\n&nbsp;* 当空白间隔小于 offset的时候，\n&nbsp;* 起点处会进入一部分线段（起点之前的线段）。\n&nbsp;* 线段是无穷循环的，\n&nbsp;* 但是都会没入结点中，超过结点后，被覆盖。\n&nbsp;*/\n$stroke_color: #19f6e8;\n$menu_w: 180px;\n$menu_h: 48px;\n$stroke_max_width: 6px;\n$stroke_min_width: 2px;\n$dash_len: 120px;\n$dash_space_len: $menu_w + $menu_h + ($menu_w - $dash_len)/2;\n$dash_offset: - $dash_space_len;\n&nbsp;\n$dash_full_len: 2*($menu_w + $menu_h);\n//======================================\n/**\n&nbsp;* A text center size\n&nbsp;*/\n$text_size: 18px;\n$text_bottom: $text_size + ($menu_h - $text_size)/2 + $stroke_min_width;\n@keyframes draw {\n&nbsp; 0% {\n&nbsp; &nbsp; stroke-dasharray: $dash_len $dash_space_len;\n&nbsp; &nbsp; stroke-dashoffset: $dash_offset;\n&nbsp; &nbsp; stroke-width: $stroke_max_width;\n&nbsp; }\n&nbsp; 100% {\n&nbsp; &nbsp; stroke-dasharray: $dash_full_len;\n&nbsp; &nbsp; stroke-dashoffset: 0;\n&nbsp; &nbsp; stroke-width: $stroke_min_width;\n&nbsp; }\n}\n/**\n&nbsp;* FIX Firefox bugs: anti-direcion，\n&nbsp;* and dashoffset is different with Chrome\n&nbsp;*/\n@keyframes moz_draw {\n&nbsp; 0% {\n&nbsp; &nbsp; stroke-dasharray: $dash_len $dash_space_len;\n&nbsp; &nbsp; stroke-dashoffset: $dash_offset;\n&nbsp; &nbsp; stroke-width: $stroke_max_width;\n&nbsp; }\n&nbsp; 100% {\n&nbsp; &nbsp; stroke-dasharray: $dash_full_len+$dash_space_len;\n&nbsp; &nbsp; stroke-dashoffset: -$dash_offset;\n&nbsp; &nbsp; stroke-width: $stroke_min_width;\n&nbsp; }\n}\n</code></pre><p style=\"margin-left: 0px;\"><br></p><p style=\"margin-left: 0px;\"><br></p><p style=\"margin-left: 0px;\">3. 这块是CSS样式</p><pre><code>\n\n      .menu {  \n        width: $menu_w;\n        height: $menu_h;\n        display: inline-block;\n        margin: 2px;\n        // margin: 0 auto;\n        text-align: center;\n        position: relative;\n\n        /**\n         * @debug Firefox和一些safair版本中，不识别CSS中的width和height\n         * 必须将width写在svg代码中\n         */\n        svg{\n          width: $menu_w;\n          height: $menu_h;\n          .shape {\n            \n            // @extend .hardware;\n\n            width: $menu_w;\n            height: $menu_h;\n\n            fill: transparent;\n            stroke-dasharray: $dash_len $dash_space_len;\n            stroke-dashoffset: $dash_offset;\n            stroke-width: 0;\n            stroke: $stroke_color;\n  \n            // 选中状态的\n            @at-root nav .menu.active svg .shape {\n              stroke-width: $stroke_max_width;\n            }\n\n          }\n        }\n\n        &amp;:hover .shape {\n          -webkit-animation: 0.5s linear 0s normal forwards 1 draw;\n          animation: 0.5s linear 0s normal forwards 1 draw;\n\n          //fix Firefox :stroke-dashoffset not 0 ??\n          @-moz-document url-prefix() {\n            animation: 0.5s linear 0s normal forwards 1 moz_draw;\n          }\n        }\n\n        .text {\n          // 具有子菜单的一级菜单，具有交互模糊效果\n          @at-root .menu.on .text{\n            @include blur(2px);\n          }\n          @include trans-all(); \n          \n          color: $nav_a_color;\n          font-size: $text_size;\n          letter-spacing: 3px;\n          line-height: $text_size;\n          position: relative;\n          bottom: $text_bottom;\n          // font-family: 'roboto';\n          text-decoration: none;          \n          \n          &amp;:hover {\n            color: $nav_a_color;\n            letter-spacing: 4px;\n          }\n        }\n      }\n\n\n</code></pre>","excerpt":"SVG动画，结合了CSS3的transition， 先看下效果图 动画效果： 直接参见本页面的导航菜单鼠标一上去，会有border变长，通过border的dashoffset的变化，包围住整个菜单矩形。用到了css3的animation，详细用法大家可以看下： http://www.ruanyifeng.com/blog/2014/02/css_transition_and_animation.html 讲的比较好注意，Firefox中跟webkit计算dash-offset方法有不同，需要fix一下：/** * FIX Firefox bugs: an","img":["/img/081b72c0-8ffa-429a-a643-fa44adc6d3a3.png"],"title":"酷酷的SVG动画菜单","author":"Cloud","type":"tech","en_gallery":false,"enable":true,"tag":["前端","UI","SVG"],"thumb":["/img/081b72c0-8ffa-429a-a643-fa44adc6d3a3.png"],"mid":["/img/081b72c0-8ffa-429a-a643-fa44adc6d3a3.png"],"createdAt":"2015-10-27T12:26:35.881Z","updatedAt":"2015-11-27T01:45:00.281Z","pv_count":3009,"article_id":"562f6d7bd6db69011de1bbdc","raw":["/img/081b72c0-8ffa-429a-a643-fa44adc6d3a3.png"],"id":"562f6d7bd6db69011de1bbdc"},{"content":"<p>　　黑白摄影从古至今一直很流行，景观摄影是一大流派，许多摄影师选择拍摄单色照片。但黑色和白色在每张照片里的效果是不一样的。它需要时间和实践，提高你对黑色白色的理解。下面这些技巧将有助于你更好的拍摄黑白风景照片。</p><p><strong>　　1.了解什么场景拍摄黑白照片更好</strong></p><p>　　有了彩色景观照片，可以依靠色彩的力量来创造内容和兴趣。良好的色彩景观摄影的关键是找到一个值得拍摄的场景，并有最美丽的光作支撑。这就是为什么这么多的彩色景观照片是在黄金时段或日落后拍摄的。</p><p>　　黑白是不同的。没有颜色，你就必须更加努力地创造出强大的作品。你需要学习寻找摄影构图的技巧，如引线，形状，图案，色调对比度和纹理。真的，你要将你看到的色彩在脑中转换成黑白，所剩下的图案就是你要学习的。</p><p>　　例如，这张黑色摄影作品，用的是双瀑布和黑暗的岩石之间的对比。</p><p style=\"text-align: center;\"><img alt=\"ceSjMjJG6580w.jpg\" src=\"/img/large/31ad11c8-debb-4f61-973d-4bd892c69520.jpg\" width=\"700\" height=\"560\"><br></p><p><strong>　　2.寻找文理和色调的对比</strong></p><p>　　色调对比度是用来描述图像的不同部分之间的亮度变化的术语。以下面的照片为例。码头，映衬着傍晚的天空，码头是黑暗的，天空则更浅。这是色调对比。海中的灰色比天空暗一点，但又亮于码头。</p><p style=\"text-align: center;\"><img alt=\"ceOCnQh07Q7cw.jpg\" src=\"/img/large/f3eaf83c-9515-49e3-a550-2b42e216acd7.jpg\" width=\"600\" height=\"600\"><br></p><p>　　如果你想在拍摄悬崖，岩石，草，树，山上出现的东西，海和人造的物体，如码头和码头他们都有不同的纹理。</p><p>　　在下面的照片中，石拱，远处的悬崖，和岩石在前景都是沉重的纹理。大海和天空都更光滑。这是岩石的粗糙度与触感和平静的海面和天空之间的强烈对比。</p><p style=\"text-align: center;\"><img alt=\"ceny4bjWodmw.jpg\" src=\"/img/large/f7c6c9d6-9da4-4d9a-b655-3c4bddec20fc.jpg\" width=\"700\" height=\"395\"><br></p><p><strong>　　3.黑白模式拍摄</strong></p><p>　　用码相机拍摄的好处是，他们可以帮助你理解黑白颜色下的世界。你所要做的就是把你的相机设置为黑白（单色）模式。然后在相机的取景器上查看当前现场的黑白效果。</p><p style=\"text-align: center;\"><img alt=\"ceZuAsO1EStIg.jpg\" src=\"/img/large/b276c816-562d-4a1a-b5e9-24b415d63926.jpg\" width=\"600\" height=\"460\"><br></p><p>　　这有助于你只看到黑色和白色，不会被其他杂乱的颜色分心。这个方法是有用的，因为它使你更容易看到色调的对比度，纹理，线条，形状，图案和光。</p><p><br></p><p><strong>　4.学习使用中灰密度滤光镜</strong></p><p>　　中灰密度滤光镜是景观摄影师的秘密武器，要了解为什么他们是如此有用，让我们思考一下景观照片的典型设置。首先，您设置您ISO尽可能低来保证最佳的图像质量。下一步，你设置一个光圈，大多数的景观照片都是在F / 11或F / 16。</p><p>　　有了这些变量，快门速度取决于环境光的水平。在明亮的阳光下，它可能是约1 / 125s。在低光，它可以低至1 / 2s。但是，如果你想使用一个较慢的快门速度创意效果呢？如果ISO和光圈是固定的，你得到更长快门速度的唯一的方式就是通过使用中灰密度滤光镜。</p><p>　　下面是一个例子。这张照片是在黄昏的光圈的F / 11在ISO 200和快门速度的1 /5th下。这是慢到水面模糊，你甚至可以看到前景的岩石。</p><p style=\"text-align: center;\"><img alt=\"1.jpg\" src=\"/img/large/b1e561be-ab30-4d91-978b-62e47492538e.jpg\" width=\"700\" height=\"395\"><br></p><p>　　然后我添加了一个中灰密度滤光镜，并使这张照片（下面）的快门速度为180秒（3分钟）。水是完全平静的，云在空中移动形成了一个条纹。</p><p style=\"text-align: center;\"><img alt=\"2.jpg\" src=\"/img/large/0e9ffe97-0abc-4176-86d8-ac9e27e699fa.jpg\" width=\"700\" height=\"395\"><br></p><p><strong>　　5.不要被其他摄影作品影响</strong></p><p>　　摄影师Cole Thompson有一个有趣的想法。他练习他所谓的摄影禁欲，不看其他摄影师的作品。该理论是，他能够通过自己的眼睛看到的景观绝不受其他人的照片的影响。</p><p style=\"text-align: center;\"><img alt=\"3.jpg\" src=\"/img/large/34cc3b0f-bd43-4091-8e58-416fc9eed2cd.jpg\" width=\"600\" height=\"600\"><br></p><p>　　我不是很相信这个极端的方法，因为当你缺乏灵感的时候，其他摄影师的作品或许会给你新的想法。但问题是，你在研究过程中看到的最优秀的摄影作品往往会印在你的脑海中。之后你的大脑自然趋势就是要创建类似的图像。这样做的结果就会导致你最后的照片看起来像其他人的。</p><p style=\"text-align: center;\"><img alt=\"4.jpg\" src=\"/img/large/4b77b067-647a-4076-8446-3950627e23bd.jpg\" width=\"700\" height=\"284\"><br></p><p><strong>　　6.旅行</strong></p><p>　　所有的照片，我已经展示给你的都是在西班牙北部拍的。除非你也足够的幸运的生活在这样一个地区，否则你需要旅行来找到类似鼓舞人心的风景照片。</p><p>　　即使你住在一个风景优美的地方，你也需要旅行来扩大你的经验，并增加你照片的深度。我最喜欢的风景照片是在旅行时拍摄的，这两个活动很好地结合在一起，当它背后有一个目的时，旅行更有趣，更令人兴奋。风景摄影是种可以给你的目的感的东西之一。</p><p style=\"text-align: center;\"><img alt=\"5.jpg\" src=\"/img/large/6e0b277c-d3aa-4c04-b255-2157cfb3d99d.jpg\" width=\"700\" height=\"467\"><br></p><p>　　没有旅行，我永远不会有经验和这么优秀的作品。</p><p>[From: <a href=\"http://www.andrewsgibson.com/blog/2016/01/the-power-of-the-black-white-landscape/\">http://www.andrewsgibson.com/blog/2016/01/the-power-of-the-black-white-landscape/</a>]</p>","excerpt":"黑白摄影从古至今一直很流行，景观摄影是一大流派，许多摄影师选择拍摄单色照片。但黑色和白色在每张照片里的效果是不一样的。它需要时间和实践，提高你对黑色白色的理解。下面这些技巧将有助于你更好的拍摄黑白风景照片。　　1.了解什么场景拍摄黑白照片更好　　有了彩色景观照片，可以依靠色彩的力量来创造内容和兴趣。良好的色彩景观摄影的关键是找到一个值得拍摄的场景，并有最美丽的光作支撑。这就是为什么这么多的彩色景观照片是在黄金时段或日落后拍摄的。　　黑白是不同的。没有颜色，你就必须更加努力地创造出强大的作品。你需要学习寻找摄影构图的技巧，如引线，形状，图案，色调对比度和纹","img":["/img/large/31ad11c8-debb-4f61-973d-4bd892c69520.jpg","/img/large/f3eaf83c-9515-49e3-a550-2b42e216acd7.jpg","/img/large/f7c6c9d6-9da4-4d9a-b655-3c4bddec20fc.jpg","/img/large/b276c816-562d-4a1a-b5e9-24b415d63926.jpg","/img/large/b1e561be-ab30-4d91-978b-62e47492538e.jpg","/img/large/0e9ffe97-0abc-4176-86d8-ac9e27e699fa.jpg","/img/large/34cc3b0f-bd43-4091-8e58-416fc9eed2cd.jpg","/img/large/4b77b067-647a-4076-8446-3950627e23bd.jpg","/img/large/6e0b277c-d3aa-4c04-b255-2157cfb3d99d.jpg"],"title":"黑白摄影技巧","author":"Andrew S. Gibson","type":"essay","en_gallery":true,"enable":true,"tag":["摄影"],"thumb":["/img/thumb/31ad11c8-debb-4f61-973d-4bd892c69520.jpg","/img/thumb/f3eaf83c-9515-49e3-a550-2b42e216acd7.jpg","/img/thumb/f7c6c9d6-9da4-4d9a-b655-3c4bddec20fc.jpg","/img/thumb/b276c816-562d-4a1a-b5e9-24b415d63926.jpg","/img/thumb/b1e561be-ab30-4d91-978b-62e47492538e.jpg","/img/thumb/0e9ffe97-0abc-4176-86d8-ac9e27e699fa.jpg","/img/thumb/34cc3b0f-bd43-4091-8e58-416fc9eed2cd.jpg","/img/thumb/4b77b067-647a-4076-8446-3950627e23bd.jpg","/img/thumb/6e0b277c-d3aa-4c04-b255-2157cfb3d99d.jpg"],"mid":["/img/mid/31ad11c8-debb-4f61-973d-4bd892c69520.jpg","/img/mid/f3eaf83c-9515-49e3-a550-2b42e216acd7.jpg","/img/mid/f7c6c9d6-9da4-4d9a-b655-3c4bddec20fc.jpg","/img/mid/b276c816-562d-4a1a-b5e9-24b415d63926.jpg","/img/mid/b1e561be-ab30-4d91-978b-62e47492538e.jpg","/img/mid/0e9ffe97-0abc-4176-86d8-ac9e27e699fa.jpg","/img/mid/34cc3b0f-bd43-4091-8e58-416fc9eed2cd.jpg","/img/mid/4b77b067-647a-4076-8446-3950627e23bd.jpg","/img/mid/6e0b277c-d3aa-4c04-b255-2157cfb3d99d.jpg"],"raw":["/img/31ad11c8-debb-4f61-973d-4bd892c69520.jpg","/img/f3eaf83c-9515-49e3-a550-2b42e216acd7.jpg","/img/f7c6c9d6-9da4-4d9a-b655-3c4bddec20fc.jpg","/img/b276c816-562d-4a1a-b5e9-24b415d63926.jpg","/img/b1e561be-ab30-4d91-978b-62e47492538e.jpg","/img/0e9ffe97-0abc-4176-86d8-ac9e27e699fa.jpg","/img/34cc3b0f-bd43-4091-8e58-416fc9eed2cd.jpg","/img/4b77b067-647a-4076-8446-3950627e23bd.jpg","/img/6e0b277c-d3aa-4c04-b255-2157cfb3d99d.jpg"],"createdAt":"2020-05-07T06:41:30.975Z","updatedAt":"2020-05-07T06:41:30.975Z","pv_count":2346,"id":"5eb3ad9a82b94de52f13b5ff"},{"content":"<blockquote><p>Русское слово</p></blockquote><p><br></p><p>2015-7-20</p><p>1. Июль : July</p><p>2. Аигуст : Autumn</p><p>3. фотография : photograph&nbsp;</p><p>4. вода : water</p><p>5. адрес : address</p><p>6. автобус : bus</p><p>7. английски : English</p><p>8. без : not exist, have not [thing]</p><p>9. воздух : the air</p><p>10. ветер : wind, breeze</p><p>11. На свете : On the world,&nbsp;</p><p>12. На : on the ...&nbsp;</p><p>13. фильмов : movie，film</p><p>2015-7-21</p><p>14. Элегантные девушка ： elegant girl</p><p>15. девушка ：girl</p><p>16. дурак :【阳】 fool ,stupid guy； дура： 【阴】; дурацкий &nbsp;【形容词】</p><p>17. очень красивый : very nice ,beautiful&nbsp;</p><p>18. самая ： the most xxx</p><p>19. сексуальная женщина ： sexy women</p><p>20. мира ： the world</p><p>2015-7-24</p><p>21. жаркая погода : hot weather</p><p>22. В моей комнате : in my room</p><p>23. большой : big, large</p><p>24. магазин ： shop, store</p><p>25. жаркая ： hot</p><p>2015-7-26</p><p>26. Я учусь ： I‘m studying</p><p>2015-7-27</p><p>27. Доброе утро : good morning</p><p>28. Привет : hi, hello</p><p>29. &nbsp;Спасибо : thanks&nbsp;</p><p>30. Нормально : fine , I am fine &nbsp;</p><p>31. восхитительна : happy, pleasure</p><p>32. добрый день : good afternoon</p><p>33. где учил русский язык ? 在哪儿学的俄语吗？</p><p>34. Я могу говорить простой русский&nbsp;</p><p>eg.</p><p>ах, русский язык ? Я могу говорить простой русский )) &nbsp; Я больше знаю с английского и китайский .</p><p>啊，俄语吗？我能说简单的俄语））我更知道英语和中文</p><p>35. Ты в пекин? &nbsp;: &nbsp;Are you in Beijing ？</p><p>36. русский язык очень интересно ： Russian is interesting</p><p>37. Да, &nbsp;я живу Пекине &nbsp;: Yes, I live in Beijing.</p><p>38. в минувшие выходные я пошел плавать ： I went swimming on last weekend</p><p>39. Ты где работаешь ? ： where do you work ?</p><p>40. работаешь ： work, do jobs</p><p>41. Какие метро станция ты живешь рядом? : which subway station do you live near?</p><p>42. &nbsp;Я только пришел домой с работы ： 我刚下班回家</p><p>43. кушай и отдыхай : eating and reset&nbsp;</p><p>44. Шел дождь . &nbsp;: It is raining.</p><p>45. Я чувствую себя очень комфортно : &nbsp;I feel very comfortable .</p><p>46. ты был в России ? : 你曾经在俄罗斯吗？&nbsp;</p><p>47. Сейчас на улице очень хорошо 😌 не жарко ： 现在大街上是很不错的😌不热</p><p>48. Почему ？： &nbsp;why？&nbsp;</p><p>49. когда вы пришли в Пекин?</p><p>50. Ты где учил русский язык ?</p><p>51. Ты умеешь разговаривать по русски ? : Can you speak in Russian?</p><p>52. больше общайся с русскими друзьями : 更多的沟通与俄罗斯朋友</p><p>53. Хорошо ： OK</p><p>54. Я хочу поехать в Москву : &nbsp;I want to go to Moscow</p><p>55. Приятного аппетита : 好好享受吃好</p><p>56. Спасибо, вы очень добры : thanks, you are so kind</p><p>57. место дая тебя : the place gives to you</p><p>58. любят ： like， like to do, love&nbsp;</p><p>59. нравлюсь ： like some one， love some one</p><p>60. то что ваш любимый китайской кушанье? ： what is your favorite Chinese dish?</p><p>61. познакомиться &nbsp;: &nbsp;认识，熟悉</p><p>2015-7-30</p><p>62. &nbsp;Мне очень нравится китайская кухня &nbsp;： I really like Chinese food</p><p>63. Мне все нравися &nbsp;： &nbsp;I like everything</p><p>64. Я люблю фотографию : I love photograph</p><p>65. Отобразить некоторые фотографию : show some photograph</p><p>2015-8-2</p><p>66. Привет, друг. Я найду тебя в VK : Hi， friend. I find you on VK</p><p>67. Я люблю тебя ： I love you&nbsp;</p><p>68. Извините： sorry</p><p>==================================</p><p>2015-9-4</p><p>69. Сегодня день рождения &nbsp;у Tom : Today is Tom's birthday.</p><p>2015-9-10&nbsp;</p><p>70. Добрый вечер： good evening</p><p>71. доброй ночи: good night</p><p>2015-9-14</p><p>72. До свидания： good bye</p><p><br></p><p><br></p><p><br></p><p>2015 - 10 -28</p><blockquote><ol><li>Это дом. :This is room</li><li>Это он. this is him</li></ol></blockquote><p><br></p><p>2015-10-31</p><p><br></p><p>как поживаете эти дни ？: how are these days ?<br></p><p><br></p><p>2015-11-30</p><p>прекрасный 非常好看的，漂亮的 &nbsp;<span style=\"color: rgb(102, 102, 102);\">~а</span><span style=\"color: rgb(255, 120, 0);\">я</span><span style=\"color: rgb(102, 102, 102);\">&nbsp;ж</span><span style=\"color: rgb(255, 120, 0);\">е</span><span style=\"color: rgb(102, 102, 102);\">нщина非常漂亮的女人.</span><br></p>","excerpt":"Русское слово2015-7-201. Июль : July2. Аигуст : Autumn3. фотография : photograph 4. вода : water5. адрес : address6. автобус : bus7. английски : English8. без : not exist, have not [thing]9. воздух : the air10. ветер : wind, breeze11. На свете : On the world, 12. На : on the ... ","title":"常用俄语","author":"Cloud","type":"essay","en_gallery":false,"enable":true,"tag":["生活","俄语"],"img":[],"thumb":[],"mid":[],"createdAt":"2015-10-27T16:25:01.790Z","updatedAt":"2015-11-30T08:58:14.778Z","pv_count":2125,"article_id":"562fa55d031ba6331fb06be7","raw":[],"id":"562fa55d031ba6331fb06be7"},{"content":"<p>去年公司在三元桥远洋新干线的时候，在楼下溜达时看到的，可爱的萝莉和正太，老爸领着在下面玩</p><p><br></p><p>1. 奔跑</p><p><img alt=\"1.jpg\" src=\"/img/large/b12bc630-59e1-4c7f-a696-2585b47471d9.jpg\" width=\"1200\" height=\"800\"><br></p><p><br></p><p>2. 看</p><p><img alt=\"2.jpg\" src=\"/img/large/9d8bc092-3dc9-4d14-8628-4897bb8afe4f.jpg\" width=\"1200\" height=\"800\"><br></p><p><br></p><p>3. 害羞</p><p><br></p><p><img alt=\"3.jpg\" src=\"/img/large/82901e1e-e2a8-4ed3-b6b6-e3446a7be949.jpg\" width=\"598\" height=\"800\"><br></p>","excerpt":"去年公司在三元桥远洋新干线的时候，在楼下溜达时看到的，可爱的萝莉和正太，老爸领着在下面玩1. 奔跑2. 看3. 害羞","img":["/img/large/b12bc630-59e1-4c7f-a696-2585b47471d9.jpg","/img/large/9d8bc092-3dc9-4d14-8628-4897bb8afe4f.jpg","/img/large/82901e1e-e2a8-4ed3-b6b6-e3446a7be949.jpg"],"title":"马思德一家","author":"Cloud","type":"essay","en_gallery":true,"enable":true,"tag":["生活","摄影","人像"],"thumb":["/img/thumb/b12bc630-59e1-4c7f-a696-2585b47471d9.jpg","/img/thumb/9d8bc092-3dc9-4d14-8628-4897bb8afe4f.jpg","/img/thumb/82901e1e-e2a8-4ed3-b6b6-e3446a7be949.jpg"],"mid":["/img/mid/b12bc630-59e1-4c7f-a696-2585b47471d9.jpg","/img/mid/9d8bc092-3dc9-4d14-8628-4897bb8afe4f.jpg","/img/mid/82901e1e-e2a8-4ed3-b6b6-e3446a7be949.jpg"],"createdAt":"2015-10-27T12:45:23.350Z","updatedAt":"2015-11-25T10:48:31.495Z","pv_count":2075,"article_id":"562f71e3c114ada21d3b866d","raw":["/img/b12bc630-59e1-4c7f-a696-2585b47471d9.jpg","/img/9d8bc092-3dc9-4d14-8628-4897bb8afe4f.jpg","/img/82901e1e-e2a8-4ed3-b6b6-e3446a7be949.jpg"],"id":"562f71e3c114ada21d3b866d"},{"content":"<p>1. 选择一个焦点</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 自动对焦时，相机会选取最近镜头的物体来对焦，容易造成对焦不准的情况，所以把自动对焦模式抛弃使用吧。选择一个对焦点，这是摄影人必须要学会的。</p><p><br></p><p style=\"margin-left: 0px;\"><img alt=\"793d5ac1-4f4d-4d76-9448-d68bd0fb0077.jpg\" src=\"http://karat.cc/img/575957eb-a1ab-4b89-ae27-89c4ef6c549d.jpg\" width=\"800\" height=\"521\"><br></p><p><br></p><p>2. 把焦点放在眼睛</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 眼睛是心灵的窗口。眼睛是脸上最敏锐的一个点，也是好照片最重要的部分。当光圈全开时，把焦点堆在眼睛，连皮肤都会模糊起来，这时候你也可以为磨皮省事了。</p><p style=\"margin-left: 0px;\"><br></p><p style=\"margin-left: 0px;\"><img alt=\"9015eee1-e203-45c2-9cc3-734c6c17d412.jpg\" src=\"http://karat.cc/img/4534a01f-c07d-4e87-bcb1-8f518bb8f6b5.jpg\" width=\"800\" height=\"533\"><br></p><p style=\"margin-left: 0px;\"><br></p><p>3. 全开光圈，小景深</p><p>　　有相当多理由的理由给你去买一个大光圈的镜头。最能引起共识的就是为了拍摄小景深效果。令人惊讶的光线效果和迷人的背景模糊，都能从大光圈里获得。</p><p><br></p><p style=\"margin-left: 0px;\"><img alt=\"5a3abbc2-fbce-4daa-9d35-b8f067dc456d.jpg\" src=\"/img/a2edeffb-e0c7-49fe-ac80-f7548c1182f9.jpg\" width=\"665\" height=\"600\"></p><p style=\"margin-left: 0px;\"><br></p><p>4. 尝试用70mm或以上的镜头拍摄</p><p>　　很多mm 看完照片后都会有这样的疑问：“为什么我的脸看上去肿了?” 。任何70mm以下的镜头拍摄都会引起不同程度的变形。长焦会产生压缩空间的效果，也能加深背景的模糊。</p><p style=\"margin-left: 0px;\"><br></p><p style=\"margin-left: 0px;\"><img alt=\"4}@T`@G_D[%9)Z6BRVFA85Y.jpg\" src=\"/img/abc16db5-4327-4601-bb37-fc2bd921ce8e.jpg\" width=\"1600\" height=\"1067\"><br></p><p style=\"margin-left: 0px;\"><br></p><p><img alt=\"bd4daef1cf63f6d5a020f34684183336.jpg\" src=\"http://karat.cc/img/7111514a-71ca-42c7-afa2-faba79675a66.jpg\" width=\"683\" height=\"1024\"><br></p><p><br></p><p><img alt=\"2cb92c03-8314-499b-b082-bb78427134c7.jpg\" src=\"http://karat.cc/img/e6a4dba5-6827-49a7-ad06-c7e3302302ae.jpg\" width=\"800\" height=\"531\"></p><p><img alt=\"M$(7VI~KNRG6_8{Y3BLJOON.jpg\" src=\"/img/e2385c65-ffb1-4a03-ad91-1d7f5d74da35.jpg\" width=\"1800\" height=\"1201\"><br></p><p style=\"margin-left: 0px;\"><br></p><p style=\"margin-left: 0px;\"><br></p><p style=\"margin-left: 0px;\"><img alt=\"4692dcc7-63c2-44dd-9ebd-ad4cf5de4c46.jpg\" src=\"/img/fd44f342-df03-4ff5-a22d-199f61bf027c.jpg\" width=\"800\" height=\"533\"><br></p><p style=\"margin-left: 0px;\"><img alt=\"`7OB7BBP@1UK]6`[T[~_`C6.jpg\" src=\"/img/641f6b22-5e55-49dc-83f5-7122a2784aa1.jpg\" width=\"1280\" height=\"1920\"><br></p><p style=\"margin-left: 0px;\"><img alt=\"222.jpg\" src=\"http://karat.cc/img/4c7233aa-39be-49b9-9a55-8dddb8413541.jpg\" width=\"652\" height=\"460\"><br></p><p style=\"margin-left: 0px;\"><br></p><p style=\"margin-left: 0px;\"><img alt=\"bf07033e-f6e0-4098-84a9-7a0bca2ba959.jpg\" src=\"/img/747244bc-6d45-4862-850a-c669772d6d19.jpg\" width=\"800\" height=\"553\"></p>","excerpt":"1. 选择一个焦点        自动对焦时，相机会选取最近镜头的物体来对焦，容易造成对焦不准的情况，所以把自动对焦模式抛弃使用吧。选择一个对焦点，这是摄影人必须要学会的。2. 把焦点放在眼睛        眼睛是心灵的窗口。眼睛是脸上最敏锐的一个点，也是好照片最重要的部分。当光圈全开时，把焦点堆在眼睛，连皮肤都会模糊起来，这时候你也可以为磨皮省事了。3. 全开光圈，小景深　　有相当多理由的理由给你去买一个大光圈的镜头。最能引起共识的就是为了拍摄小景深效果。令人惊讶的光线效果和迷人的背景模糊，都能从大光圈里获得。4. 尝试用70mm或以上的镜头拍摄　　很","img":["http://karat.cc/img/575957eb-a1ab-4b89-ae27-89c4ef6c549d.jpg","http://karat.cc/img/4534a01f-c07d-4e87-bcb1-8f518bb8f6b5.jpg","/img/a2edeffb-e0c7-49fe-ac80-f7548c1182f9.jpg","/img/abc16db5-4327-4601-bb37-fc2bd921ce8e.jpg","http://karat.cc/img/7111514a-71ca-42c7-afa2-faba79675a66.jpg","http://karat.cc/img/e6a4dba5-6827-49a7-ad06-c7e3302302ae.jpg","/img/e2385c65-ffb1-4a03-ad91-1d7f5d74da35.jpg","/img/fd44f342-df03-4ff5-a22d-199f61bf027c.jpg","/img/641f6b22-5e55-49dc-83f5-7122a2784aa1.jpg","http://karat.cc/img/4c7233aa-39be-49b9-9a55-8dddb8413541.jpg","/img/747244bc-6d45-4862-850a-c669772d6d19.jpg"],"title":"几组街拍和人像摄影","author":"Cloud","type":"essay","en_gallery":true,"enable":true,"tag":["摄影","人像"],"thumb":["http://karat.cc/img/thumb/575957eb-a1ab-4b89-ae27-89c4ef6c549d.jpg","http://karat.cc/img/thumb/4534a01f-c07d-4e87-bcb1-8f518bb8f6b5.jpg","/img/thumb/a2edeffb-e0c7-49fe-ac80-f7548c1182f9.jpg","/img/thumb/abc16db5-4327-4601-bb37-fc2bd921ce8e.jpg","http://karat.cc/img/thumb/7111514a-71ca-42c7-afa2-faba79675a66.jpg","http://karat.cc/img/thumb/e6a4dba5-6827-49a7-ad06-c7e3302302ae.jpg","/img/thumb/e2385c65-ffb1-4a03-ad91-1d7f5d74da35.jpg","/img/thumb/fd44f342-df03-4ff5-a22d-199f61bf027c.jpg","/img/thumb/641f6b22-5e55-49dc-83f5-7122a2784aa1.jpg","http://karat.cc/img/thumb/4c7233aa-39be-49b9-9a55-8dddb8413541.jpg","/img/thumb/747244bc-6d45-4862-850a-c669772d6d19.jpg"],"mid":["http://karat.cc/img/mid/575957eb-a1ab-4b89-ae27-89c4ef6c549d.jpg","http://karat.cc/img/mid/4534a01f-c07d-4e87-bcb1-8f518bb8f6b5.jpg","/img/mid/a2edeffb-e0c7-49fe-ac80-f7548c1182f9.jpg","/img/mid/abc16db5-4327-4601-bb37-fc2bd921ce8e.jpg","http://karat.cc/img/mid/7111514a-71ca-42c7-afa2-faba79675a66.jpg","http://karat.cc/img/mid/e6a4dba5-6827-49a7-ad06-c7e3302302ae.jpg","/img/mid/e2385c65-ffb1-4a03-ad91-1d7f5d74da35.jpg","/img/mid/fd44f342-df03-4ff5-a22d-199f61bf027c.jpg","/img/mid/641f6b22-5e55-49dc-83f5-7122a2784aa1.jpg","http://karat.cc/img/mid/4c7233aa-39be-49b9-9a55-8dddb8413541.jpg","/img/mid/747244bc-6d45-4862-850a-c669772d6d19.jpg"],"createdAt":"2015-10-27T11:16:38.727Z","updatedAt":"2015-10-30T08:42:01.429Z","pv_count":2049,"article_id":"562f5d16aab8c5ee1a16005c","id":"562f5d16aab8c5ee1a16005c"},{"content":"<p><img alt=\"4a7f6fdbd58b4b29a783b9530e83d99c.jpg\" src=\"/img/large/6f868e96-67e7-4da0-b92a-56f5dc73ae56.jpg\" width=\"640\" height=\"406\"><br></p><p><br></p><p>所谓人像摄影，就是以人物为主要创作对象的摄影形式。人像摄影与一般的人物摄影不同：人像摄影以刻画与表现被摄者的具体相貌和神态为自身的首要创作任务，虽然有些人像摄影作品也包含一定的情节，但它仍以表现被照者的相貌为主。那么，我们今天来讨论下人像的相机参数吧！</p><p>标准的人像摄影镜头，一般是指在镜头1.5m—2m的距离上照人的镜头，也就是70mm-135mm的镜头。按照一般的美学观点，在1.5至2米外看一个人的五官是最漂亮的。比方说如果想要拍摄带环境的人像，建议选择 50mm 以下的镜头，而如果想要拍半身以上的肖像照并且有很明显的虚化将主体和背景分离，那么 85mm 以上的中长焦镜头可能是更好的选择。</p><p><br></p><p><img alt=\"2954a9b0c96f4a458cb1b6d2ddfd12a6.jpg\" src=\"/img/large/173b8f80-20ea-408f-b160-6ca917f5aa51.jpg\" width=\"640\" height=\"459\"><br></p><p>好用的头就是又容易与被拍摄人沟通，又不发生明显的变形的镜头。</p><p>对于135相机来说，70mm-135mm镜头是公认的人像镜头。</p><p>而对于APS-C相机来说，因为同样的镜头能得到的像场比135相机小，所以50mm-90mm焦距的135相机镜头才是APS-C相机的人像镜头。</p><p>那如果是拍儿童呢？按理说我们要用比普通人像镜头焦距更大（放大倍数更大）的镜头才能使小孩的头肩充满整个像场，但是由于儿童的五官没有成人那么突出，我们可以在更近的距离拍摄而不影响审美，所以我们用普通人像镜头在1米外拍就行了。</p><p><br></p><p><img alt=\"8f2174d3f3e54c35b98d36479b006b60.jpg\" src=\"/img/large/6e6aa160-73e0-4d32-a354-b66e55cb5a1a.jpg\" width=\"500\" height=\"700\"><br></p><p>想要背景虚化，仅仅靠开大光圈是不够的，它需要满足三个要素，一是光圈，还有就是镜头的焦段和主体的位置。</p><p>简单来说，在其他两个元素不变的前提下，光圈越大，景深越浅，虚化效果就越明显。</p><p>同样的，镜头的焦段越长，虚化效果也就越明显，比方说，在人像在画面中的大小不变的前提下，85mm f/2.8 的虚化效果肯定要比 50mm f/2.8 的虚化效果要好，而就算是 35mm f/2 的虚化效果，可能都不如 85mm f/4 的虚化效果来的好。</p><p><br></p><p><img alt=\"47ecb8adf9004a6cbd67cdda7d7932ea.jpg\" src=\"/img/large/66db5f18-6bdb-4fd4-b761-26bdda06fd44.jpg\" width=\"826\" height=\"526\"><br></p><p>而想要拍出更明显的虚化效果，还需要第三个要素作用，就是被摄主体的位置，同样，也是在其他两个要素相同的前提下，主体距离拍摄者（相机）越近，或者主体距离背景越远，虚化效果就越明显。</p><p>但是要明确的一个观点是，并不是景深越浅越好，就拿肖像照来说，太浅的景深也会导致面部部分失去焦点，同时也并不是所有镜头都是最大光圈可用的，大部分镜头开足光圈会不可避免的带来锐度的损失，让画面模糊，一切都还是要以合适为主，不能一味的追求极端。</p><p><img alt=\"4e657d161c5e487aa6f33ba7a42f232f.jpg\" src=\"/img/large/93fcfcc0-e796-4a80-9688-b201f72d30a8.jpg\" width=\"500\" height=\"751\"><br></p><p>在光线充足的环境下，快门并不是一个很重要的问题，拍摄静止人像的时候，在安全快门以上就可以，但是如果想要拍摄运动中的人像，就得提高快门速度，如果是弱光环境，会比较难办，只能通过开大光圈或者增加感光度来解决。但是有的时候即使光圈开到最大也不足以满足快门，感光度拉的太高又会影响画质，因此在弱光环境下拍摄还是要多试验，根据现场光线来选择最合适的设置以免拍出自己并不满意的照片。</p><p>虽然在弱光环境下并不容易捕捉高速运动中的人，但是我们也可以利用慢快门来捕捉人物运动的轨迹。思想是活的，就看你能想到什么样的画面，然后用技术去实现它。</p><p><img alt=\"26b20b950f034f488dece6488043af96.jpg\" src=\"/img/large/3e7fc3d0-4b5e-45d4-895e-ecc6a96005df.jpg\" width=\"1080\" height=\"716\"><br></p><p>而感光度则是一个更加单纯的因素，每一台相机的高感的处理能力都不同，有些相机可以使用高达 6400 的感光度也能够拍出让自己满意的画面，而有些相机感光度超过 1600 可能就难以接受。拉高感光度所产生的噪点不同于胶片产生的颗粒，胶片颗粒的规则性会带来一定的美感，而杂乱的噪点只会让人想到古老电视机屏幕上的雪花点，看起来很不舒服。因此，高感的选择取决于你对你自己的相机的理解，在你认为可以接受的高感范围内，选择合适的感光度。</p><p><br></p><p><img alt=\"0905ef1735004c7190e2c1e26cd833ca.jpg\" src=\"/img/large/ef528c18-2546-4936-b267-293c9a6b6628.jpg\" width=\"605\" height=\"800\"><br></p><p><br></p><p><br></p><p><br></p><p>[转自：<a href=\"https://www.sohu.com/a/255093120_99931854\">https://www.sohu.com/a/255093120_99931854</a> ]</p>","excerpt":"所谓人像摄影，就是以人物为主要创作对象的摄影形式。人像摄影与一般的人物摄影不同：人像摄影以刻画与表现被摄者的具体相貌和神态为自身的首要创作任务，虽然有些人像摄影作品也包含一定的情节，但它仍以表现被照者的相貌为主。那么，我们今天来讨论下人像的相机参数吧！标准的人像摄影镜头，一般是指在镜头1.5m—2m的距离上照人的镜头，也就是70mm-135mm的镜头。按照一般的美学观点，在1.5至2米外看一个人的五官是最漂亮的。比方说如果想要拍摄带环境的人像，建议选择 50mm 以下的镜头，而如果想要拍半身以上的肖像照并且有很明显的虚化将主体和背景分离，那么 85mm ","img":["/img/large/6f868e96-67e7-4da0-b92a-56f5dc73ae56.jpg","/img/large/173b8f80-20ea-408f-b160-6ca917f5aa51.jpg","/img/large/6e6aa160-73e0-4d32-a354-b66e55cb5a1a.jpg","/img/large/66db5f18-6bdb-4fd4-b761-26bdda06fd44.jpg","/img/large/93fcfcc0-e796-4a80-9688-b201f72d30a8.jpg","/img/large/3e7fc3d0-4b5e-45d4-895e-ecc6a96005df.jpg","/img/large/ef528c18-2546-4936-b267-293c9a6b6628.jpg"],"title":"单反人像摄影技巧","author":"Sohu","type":"essay","en_gallery":true,"enable":true,"tag":["摄影","人像"],"thumb":["/img/thumb/6f868e96-67e7-4da0-b92a-56f5dc73ae56.jpg","/img/thumb/173b8f80-20ea-408f-b160-6ca917f5aa51.jpg","/img/thumb/6e6aa160-73e0-4d32-a354-b66e55cb5a1a.jpg","/img/thumb/66db5f18-6bdb-4fd4-b761-26bdda06fd44.jpg","/img/thumb/93fcfcc0-e796-4a80-9688-b201f72d30a8.jpg","/img/thumb/3e7fc3d0-4b5e-45d4-895e-ecc6a96005df.jpg","/img/thumb/ef528c18-2546-4936-b267-293c9a6b6628.jpg"],"mid":["/img/mid/6f868e96-67e7-4da0-b92a-56f5dc73ae56.jpg","/img/mid/173b8f80-20ea-408f-b160-6ca917f5aa51.jpg","/img/mid/6e6aa160-73e0-4d32-a354-b66e55cb5a1a.jpg","/img/mid/66db5f18-6bdb-4fd4-b761-26bdda06fd44.jpg","/img/mid/93fcfcc0-e796-4a80-9688-b201f72d30a8.jpg","/img/mid/3e7fc3d0-4b5e-45d4-895e-ecc6a96005df.jpg","/img/mid/ef528c18-2546-4936-b267-293c9a6b6628.jpg"],"raw":["/img/6f868e96-67e7-4da0-b92a-56f5dc73ae56.jpg","/img/173b8f80-20ea-408f-b160-6ca917f5aa51.jpg","/img/6e6aa160-73e0-4d32-a354-b66e55cb5a1a.jpg","/img/66db5f18-6bdb-4fd4-b761-26bdda06fd44.jpg","/img/93fcfcc0-e796-4a80-9688-b201f72d30a8.jpg","/img/3e7fc3d0-4b5e-45d4-895e-ecc6a96005df.jpg","/img/ef528c18-2546-4936-b267-293c9a6b6628.jpg"],"createdAt":"2020-05-07T06:25:49.545Z","updatedAt":"2020-05-07T06:25:49.545Z","pv_count":2040,"id":"5eb3a9ed82b94de52f13b5fd"},{"content":"<h1><span style=\"color: rgb(51, 51, 51);\"><br></span></h1><h1><span style=\"color: rgb(51, 51, 51);\">转自：<a taget=\"_blank\" href=\"http://www.ruanyifeng.com/blog/2015/09/web-page-performance-in-depth.html\" rel=\"nofollow\">http://www.ruanyifeng.com/blog/2015/09/web-page-performance-in-depth.html</a></span><br></h1><p>作者： 阮一峰&nbsp;<br></p><p><br></p><p><br></p><p>你遇到过性能很差的网页吗？</p><p>这种网页响应非常缓慢，占用大量的CPU和内存，浏览起来常常有卡顿，页面的动画效果也不流畅。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091508.jpg\" alt=\"\"></p><p>你会有什么反应？我猜想，大多数用户会关闭这个页面，改为访问其他网站。作为一个开发者，肯定不愿意看到这种情况，那么怎样才能提高性能呢？</p><p>本文将详细介绍性能问题的出现原因，以及解决方法。</p><h2>一、网页生成的过程</h2><p>要理解网页性能为什么不好，就要了解网页是怎么生成的。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091501.png\" alt=\"\"></p><p>网页的生成过程，大致可以分成五步。</p><blockquote><ol><li>HTML代码转化成DOM</li><li>CSS代码转化成CSSOM（CSS Object Model）</li><li>结合DOM和CSSOM，生成一棵渲染树（包含每个节点的视觉信息）</li><li>生成布局（layout），即将所有渲染树的所有节点进行平面合成</li><li>将布局绘制（paint）在屏幕上</li></ol></blockquote><p>这五步里面，第一步到第三步都非常快，耗时的是第四步和第五步。</p><p>\"生成布局\"（flow）和\"绘制\"（paint）这两步，合称为\"渲染\"（render）。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091502.png\" alt=\"\"></p><h2>二、重排和重绘</h2><p>网页生成的时候，至少会渲染一次。用户访问的过程中，还会不断重新渲染。</p><p>以下三种情况，会导致网页重新渲染。</p><blockquote><ul><li>修改DOM</li><li>修改样式表</li><li>用户事件（比如鼠标悬停、页面滚动、输入框键入文字、改变窗口大小等等）</li></ul></blockquote><p>重新渲染，就需要重新生成布局和重新绘制。前者叫做\"重排\"（reflow），后者叫做\"重绘\"（repaint）。</p><p>需要注意的是，\"重绘\"不一定需要\"重排\"，比如改变某个网页元素的颜色，就只会触发\"重绘\"，不会触发\"重排\"，因为布局没有改变。但是，\"重排\"必然导致\"重绘\"，比如改变一个网页元素的位置，就会同时触发\"重排\"和\"重绘\"，因为布局改变了。</p><h2>三、对于性能的影响</h2><p>重排和重绘会不断触发，这是不可避免的。但是，它们非常耗费资源，是导致网页性能低下的根本原因。</p><p>提高网页性能，就是要降低\"重排\"和\"重绘\"的频率和成本，尽量少触发重新渲染。</p><p>前面提到，DOM变动和样式变动，都会触发重新渲染。但是，浏览器已经很智能了，会尽量把所有的变动集中在一起，排成一个队列，然后一次性执行，尽量避免多次重新渲染。</p><blockquote><p><br></p><pre><code>div<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>color <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">'blue'</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\ndiv<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>marginTop <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">'30px'</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n</code></pre><p><br></p></blockquote><p>上面代码中，div元素有两个样式变动，但是浏览器只会触发一次重排和重绘。</p><p>如果写得不好，就会触发两次重排和重绘。</p><blockquote><p><br></p><pre><code class=\"lang-js\">div<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>color <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">'blue'</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n<span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">var</span> margin <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">parseInt<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>div<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>marginTop<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\ndiv<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>marginTop <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span>margin <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">10</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">'px'</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n</code></pre><p><br></p></blockquote><p>上面代码对div元素设置背景色以后，第二行要求浏览器给出该元素的位置，所以浏览器不得不立即重排。</p><p>一般来说，样式的写操作之后，如果有下面这些属性的读操作，都会引发浏览器立即重新渲染。</p><blockquote><ul><li>offsetTop/offsetLeft/offsetWidth/offsetHeight</li><li>scrollTop/scrollLeft/scrollWidth/scrollHeight</li><li>clientTop/clientLeft/clientWidth/clientHeight</li><li>getComputedStyle()</li></ul></blockquote><p>所以，从性能角度考虑，尽量不要把读操作和写操作，放在一个语句里面。</p><blockquote><p><br></p><pre><code class=\"lang-js\"><span class=\"token comment\" spellcheck=\"true\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: slategray;\">\n// bad\n</span>div<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>left <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> div<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>offsetLeft <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">10</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">\"px\"</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\ndiv<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>top <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> div<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>offsetTop <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">10</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">\"px\"</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n<span class=\"token comment\" spellcheck=\"true\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: slategray;\">\n// good\n</span><span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">var</span> left <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> div<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>offsetLeft<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n<span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">var</span> top  <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> div<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>offsetTop<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\ndiv<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>left <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> left <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">10</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">\"px\"</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\ndiv<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>top <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> top <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">10</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">\"px\"</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n</code></pre><p><br></p></blockquote><p>一般的规则是：</p><blockquote><ul><li>样式表越简单，重排和重绘就越快。</li><li>重排和重绘的DOM元素层级越高，成本就越高。</li><li>table元素的重排和重绘成本，要高于div元素</li></ul></blockquote><h2>四、提高性能的九个技巧</h2><p>有一些技巧，可以降低浏览器重新渲染的频率和成本。</p><p>第一条是上一节说到的，DOM 的多个读操作（或多个写操作），应该放在一起。不要两个读操作之间，加入一个写操作。</p><p>第二条，如果某个样式是通过重排得到的，那么最好缓存结果。避免下一次用到的时候，浏览器又要重排。</p><p>第三条，不要一条条地改变样式，而要通过改变class，或者csstext属性，一次性地改变样式。</p><blockquote><p><br></p><pre><code class=\"lang-js\"><span class=\"token comment\" spellcheck=\"true\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: slategray;\">\n// bad\n</span><span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">var</span> left <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">10</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n<span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">var</span> top <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">10</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\nel<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>left <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> left <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">\"px\"</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\nel<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>top  <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> top  <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">\"px\"</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n<span class=\"token comment\" spellcheck=\"true\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: slategray;\">\n// good \n</span>el<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>className <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span><span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">\" theclassname\"</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n<span class=\"token comment\" spellcheck=\"true\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: slategray;\">\n// good\n</span>el<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>cssText <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span><span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">\"; left: \"</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> left <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">\"px; top: \"</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> top <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">\"px;\"</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n</code></pre><p><br></p></blockquote><p>第四条，尽量使用离线DOM，而不是真实的网面DOM，来改变元素样式。比如，操作Document Fragment对象，完成后再把这个对象加入DOM。再比如，使用 cloneNode() 方法，在克隆的节点上进行操作，然后再用克隆的节点替换原始节点。</p><p>第五条，先将元素设为<code>display: none</code>（需要1次重排和重绘），然后对这个节点进行100次操作，最后再恢复显示（需要1次重排和重绘）。这样一来，你就用两次重新渲染，取代了可能高达100次的重新渲染。</p><p>第六条，position属性为<code>absolute</code>或<code>fixed</code>的元素，重排的开销会比较小，因为不用考虑它对其他元素的影响。</p><p>第七条，只在必要的时候，才将元素的display属性为可见，因为不可见的元素不影响重排和重绘。另外，<code>visibility : hidden</code>的元素只对重绘有影响，不影响重排。</p><p>第八条，使用虚拟DOM的脚本库，比如React等。</p><p>第九条，使用 window.requestAnimationFrame()、window.requestIdleCallback() 这两个方法调节重新渲染（详见后文）。</p><h2>五、刷新率</h2><p>很多时候，密集的重新渲染是无法避免的，比如scroll事件的回调函数和网页动画。</p><p>网页动画的每一帧（frame）都是一次重新渲染。每秒低于24帧的动画，人眼就能感受到停顿。一般的网页动画，需要达到每秒30帧到60帧的频率，才能比较流畅。如果能达到每秒70帧甚至80帧，就会极其流畅。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091509.jpg\" alt=\"\"></p><p>大多数显示器的刷新频率是60Hz，为了与系统一致，以及节省电力，浏览器会自动按照这个频率，刷新动画（如果可以做到的话）。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091510.jpg\" alt=\"\"></p><p>所以，如果网页动画能够做到每秒60帧，就会跟显示器同步刷新，达到最佳的视觉效果。这意味着，一秒之内进行60次重新渲染，每次重新渲染的时间不能超过16.66毫秒。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091511.png\" alt=\"\"></p><p>一秒之间能够完成多少次重新渲染，这个指标就被称为\"刷新率\"，英文为FPS（frame per second）。60次重新渲染，就是60FPS。</p><p>如果想达到60帧的刷新率，就意味着JavaScript线程每个任务的耗时，必须少于16毫秒。一个解决办法是使用Web Worker，主线程只用于UI渲染，然后跟UI渲染不相干的任务，都放在Worker线程。</p><h2>六、开发者工具的Timeline面板</h2><p>Chrome浏览器开发者工具的Timeline面板，是查看\"刷新率\"的最佳工具。这一节介绍如何使用这个工具。</p><p>首先，按下 F12 打开\"开发者工具\"，切换到Timeline面板。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091512.png\" alt=\"\"></p><p>左上角有一个灰色的圆点，这是录制按钮，按下它会变成红色。然后，在网页上进行一些操作，再按一次按钮完成录制。</p><p>Timeline面板提供两种查看方式：横条的是\"事件模式\"（Event Mode），显示重新渲染的各种事件所耗费的时间；竖条的是\"帧模式\"（Frame Mode），显示每一帧的时间耗费在哪里。</p><p>先看\"事件模式\"，你可以从中判断，性能问题发生在哪个环节，是JavaScript的执行，还是渲染？</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091514.png\" alt=\"\"></p><p>不同的颜色表示不同的事件。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091503.png\" alt=\"\"></p><blockquote><ul><li>蓝色：网络通信和HTML解析</li><li>黄色：JavaScript执行</li><li>紫色：样式计算和布局，即重排</li><li>绿色：重绘</li></ul></blockquote><p>哪种色块比较多，就说明性能耗费在那里。色块越长，问题越大。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091515.png\" alt=\"\"></p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091516.png\" alt=\"\"></p><p>帧模式（Frames mode）用来查看单个帧的耗时情况。每帧的色柱高度越低越好，表示耗时少。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091505.png\" alt=\"\"></p><p>你可以看到，帧模式有两条水平的参考线。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091517.png\" alt=\"\"></p><p>下面的一条是60FPS，低于这条线，可以达到每秒60帧；上面的一条是30FPS，低于这条线，可以达到每秒30次渲染。如果色柱都超过30FPS，这个网页就有性能问题了。</p><p>此外，还可以查看某个区间的耗时情况。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091518.png\" alt=\"\"></p><p>或者点击每一帧，查看该帧的时间构成。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091519.png\" alt=\"\"></p><h2>七、window.requestAnimationFrame()</h2><p>有一些JavaScript方法可以调节重新渲染，大幅提高网页性能。</p><p>其中最重要的，就是 window.requestAnimationFrame() 方法。它可以将某些代码放到下一次重新渲染时执行。</p><blockquote><p><br></p><pre><code class=\"lang-js\"><span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">function</span> <span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">doubleHeight<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>element<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">{</span>\n  <span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">var</span> currentHeight <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> element<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>clientHeight<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n  element<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>height <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span>currentHeight <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">*</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">2</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">'px'</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">}</span>\nelements<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span><span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">forEach<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>doubleHeight<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n</code></pre><p><br></p></blockquote><p>上面的代码使用循环操作，将每个元素的高度都增加一倍。可是，每次循环都是，读操作后面跟着一个写操作。这会在短时间内触发大量的重新渲染，显然对于网页性能很不利。</p><p>我们可以使用<code>window.requestAnimationFrame()</code>，让读操作和写操作分离，把所有的写操作放到下一次重新渲染。</p><blockquote><p><br></p><pre><code><span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">function</span> <span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">doubleHeight<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>element<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">{</span>\n  <span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">var</span> currentHeight <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> element<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>clientHeight<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n  window<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span><span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">requestAnimationFrame<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span><span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">function</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">{</span>\n    element<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>height <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span>currentHeight <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">*</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">2</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">'px'</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n  <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">}</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">}</span>\nelements<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span><span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">forEach<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>doubleHeight<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n</code></pre><p><br></p></blockquote><p>页面滚动事件（scroll）的监听函数，就很适合用 window.requestAnimationFrame() ，推迟到下一次重新渲染。</p><blockquote><p><br></p><pre><code>$<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span>window<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span><span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">on<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span><span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">'scroll'</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">,</span> <span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">function</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">{</span>\n   window<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span><span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">requestAnimationFrame<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>scrollHandler<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">}</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n</code></pre><p><br></p></blockquote><p>当然，最适用的场合还是网页动画。下面是一个旋转动画的例子，元素每一帧旋转1度。</p><blockquote><p><br></p><pre><code><span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">var</span> rAF <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> window<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>requestAnimationFrame<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n\n<span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">var</span> degrees <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">0</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n<span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">function</span> <span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">update<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">{</span>\n  div<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>transform <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">\"rotate(\"</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> degrees <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">\"deg)\"</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n  console<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span><span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">log<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span><span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">'updated to degrees '</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> degrees<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n  degrees <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> degrees <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">1</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n  <span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">rAF<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>update<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">}</span>\n<span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">rAF<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>update<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n</code></pre><p><br></p></blockquote><h2><br></h2><h2><br></h2><h2>八、window.requestIdleCallback()</h2><p>还有一个函数<a href=\"https://w3c.github.io/requestidlecallback/\" target=\"_blank\">window.requestIdleCallback()</a>，也可以用来调节重新渲染。</p><p>它指定只有当一帧的末尾有空闲时间，才会执行回调函数。</p><blockquote><p><br></p><pre><code class=\"lang-js\"><span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">requestIdleCallback<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>fn<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n</code></pre><p><br></p></blockquote><p>上面代码中，只有当前帧的运行时间小于16.66ms时，函数fn才会执行。否则，就推迟到下一帧，如果下一帧也没有空闲时间，就推迟到下下一帧，以此类推。</p><p>它还可以接受第二个参数，表示指定的毫秒数。如果在指定 的这段时间之内，每一帧都没有空闲时间，那么函数fn将会强制执行。</p><blockquote><p><br></p><pre><code class=\"lang-js\"><span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">requestIdleCallback<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>fn<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">,</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">5000</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n</code></pre><p><br></p></blockquote><p>上面的代码表示，函数fn最迟会在5000毫秒之后执行。</p><p>函数 fn 可以接受一个 deadline 对象作为参数。</p><blockquote><p><br></p><pre><code class=\"lang-js\"><span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">requestIdleCallback<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span><span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">function</span> <span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">someHeavyComputation<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>deadline<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">{</span>\n  <span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">while</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span>deadline<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span><span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">timeRemaining<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">&gt;</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">0</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">{</span>\n    <span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">doWorkIfNeeded<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n  <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">}</span>\n\n  <span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">if</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span>thereIsMoreWorkToDo<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">{</span>\n    <span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">requestIdleCallback<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>someHeavyComputation<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n  <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">}</span>\n<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">}</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n</code></pre><p><br></p></blockquote><p>上面代码中，回调函数 someHeavyComputation 的参数是一个 deadline 对象。</p><p>deadline对象有一个方法和一个属性：timeRemaining() 和 didTimeout。</p><p><br></p><p>（1）timeRemaining() 方法</p><p>timeRemaining() 方法返回当前帧还剩余的毫秒。这个方法只能读，不能写，而且会动态更新。因此可以不断检查这个属性，如果还有剩余时间的话，就不断执行某些任务。一旦这个属性等于0，就把任务分配到下一轮<code>requestIdleCallback</code>。</p><p>前面的示例代码之中，只要当前帧还有空闲时间，就不断调用doWorkIfNeeded方法。一旦没有空闲时间，但是任务还没有全执行，就分配到下一轮<code>requestIdleCallback</code>。</p><p><br></p><p>（2）didTimeout属性</p><p>deadline对象的&nbsp;<code>didTimeout</code>&nbsp;属性会返回一个布尔值，表示指定的时间是否过期。这意味着，如果回调函数由于指定时间过期而触发，那么你会得到两个结果。</p><blockquote><ul><li>timeRemaining方法返回0</li><li>didTimeout 属性等于 true</li></ul></blockquote><p>因此，如果回调函数执行了，无非是两种原因：当前帧有空闲时间，或者指定时间到了。</p><blockquote><p><br></p><pre><code class=\"lang-js\"><span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">function</span> myNonEssentialWork <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span>deadline<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">{</span>\n  <span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">while</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span>deadline<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span><span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">timeRemaining<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">&gt;</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">0</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">||</span> deadline<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>didTimeout<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">&amp;&amp;</span> tasks<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>length <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">&gt;</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">0</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span>\n    <span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">doWorkIfNeeded<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n\n  <span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">if</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span>tasks<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>length <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">&gt;</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">0</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span>\n    <span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">requestIdleCallback<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>myNonEssentialWork<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">}</span>\n\n<span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">requestIdleCallback<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>myNonEssentialWork<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">,</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">5000</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n</code></pre><p><br></p></blockquote><p>上面代码确保了，doWorkIfNeeded 函数一定会在将来某个比较空闲的时间（或者在指定时间过期后）得到反复执行。</p><p>requestIdleCallback 是一个很新的函数，刚刚引入标准，目前只有Chrome支持，不过其他浏览器可以用<a href=\"https://gist.github.com/paullewis/55efe5d6f05434a96c36\" target=\"_blank\">垫片库</a>。</p><h2><br></h2><h2><br></h2><h2>九、参考链接</h2><ul><li>Domenico De Felice,&nbsp;<a href=\"http://domenicodefelice.blogspot.sg/2015/08/how-browsers-work.html\" target=\"_blank\">How browsers work</a></li><li>Stoyan Stefanov,&nbsp;<a href=\"http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/\" target=\"_blank\">Rendering: repaint, reflow/relayout, restyle</a></li><li>Addy Osmani,&nbsp;<a href=\"http://addyosmani.com/blog/performance-optimisation-with-timeline-profiles/\" target=\"_blank\">Improving Web App Performance With the Chrome DevTools Timeline and Profiles</a></li><li>Tom Wiltzius,&nbsp;<a href=\"http://www.html5rocks.com/en/tutorials/speed/rendering/\" target=\"_blank\">Jank Busting for Better Rendering Performance</a></li><li>Paul Lewis,&nbsp;<a href=\"https://developers.google.com/web/updates/2015/08/27/using-requestidlecallback?hl=en\" target=\"_blank\">Using requestIdleCallback</a></li></ul><p>（完）</p>","excerpt":"转自：http://www.ruanyifeng.com/blog/2015/09/web-page-performance-in-depth.html作者： 阮一峰 你遇到过性能很差的网页吗？这种网页响应非常缓慢，占用大量的CPU和内存，浏览起来常常有卡顿，页面的动画效果也不流畅。你会有什么反应？我猜想，大多数用户会关闭这个页面，改为访问其他网站。作为一个开发者，肯定不愿意看到这种情况，那么怎样才能提高性能呢？本文将详细介绍性能问题的出现原因，以及解决方法。一、网页生成的过程要理解网页性能为什么不好，就要了解网页是怎么生成的。网页的生成过程，大致可以分","img":["http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091508.jpg","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091501.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091502.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091509.jpg","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091510.jpg","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091511.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091512.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091514.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091503.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091515.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091516.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091505.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091517.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091518.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091519.png"],"title":"网页性能管理详解","author":"阮一峰 ","type":"tech","en_gallery":false,"enable":true,"tag":["前端","Web"],"thumb":["http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091508.jpg","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091501.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091502.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091509.jpg","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091510.jpg","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091511.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091512.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091514.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091503.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091515.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091516.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091505.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091517.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091518.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091519.png"],"mid":["http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091508.jpg","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091501.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091502.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091509.jpg","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091510.jpg","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091511.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091512.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091514.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091503.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091515.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091516.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091505.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091517.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091518.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091519.png"],"raw":["http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091508.jpg","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091501.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091502.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091509.jpg","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091510.jpg","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091511.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091512.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091514.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091503.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091515.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091516.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091505.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091517.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091518.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091519.png"],"createdAt":"2015-12-05T05:08:25.460Z","updatedAt":"2015-12-05T05:11:48.574Z","pv_count":1923,"article_id":"56627149dbde3d97180380d3","id":"56627149dbde3d97180380d3"}],"tag":"前端"}