<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>元彦</title>
 <link href="https://yuanyan.github.io/atom.xml" rel="self"/>
 <link href="https://yuanyan.github.io"/>
 <updated>2026-06-01T07:43:18+00:00</updated>
 <id>https://yuanyan.github.io</id>
 <author>
   <name>元彦</name>
   <email>yuanyan.cao@gmail.com</email>
 </author>

 
 <entry>
   <title>停不下来的前端</title>
   <link href="https://yuanyan.github.io/solution/auto-workflow"/>
   <updated>2014-01-04T00:00:00+00:00</updated>
   <id>hhttps://yuanyan.github.io/solution/auto-workflow</id>
   <content type="html">
&lt;h2 id=&quot;流程&quot;&gt;流程&lt;/h2&gt;

&lt;p&gt;关于流程，是从项目启动到发布的过程。在前端通常我们都做些什么？&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;切图，即从设计稿中获取需要的素材，并不是所有前端开发都被要求切图，也不是所有前端开发都会切图，但请享受学习新知识的过程吧。&lt;/li&gt;
  &lt;li&gt;创建模版（html、jade、haml）、脚本（javascript、coffeescript）、样式（css、less、sass、stylus）文件，搭建基础的项目骨架。&lt;/li&gt;
  &lt;li&gt;文件（jade、coffeescript、less、sass…）编译&lt;/li&gt;
  &lt;li&gt;执行测试用例&lt;/li&gt;
  &lt;li&gt;代码检测&lt;/li&gt;
  &lt;li&gt;移除调试代码&lt;/li&gt;
  &lt;li&gt;静态资源合并与优化&lt;/li&gt;
  &lt;li&gt;静态资源通过hash计算指纹化&lt;/li&gt;
  &lt;li&gt;部署测试环境&lt;/li&gt;
  &lt;li&gt;灰度发布现网&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;工具化&quot;&gt;工具化&lt;/h2&gt;

&lt;p&gt;每个流程中的过程单元，我们抽象为一个Task，即任务。把可重复规则的过程进行工具化，如把JavaScript代码压缩过程工具化，而UglifyJS是具体执行任务的工具，CSS代码压缩器CleanCSS是具体执行任务的工具。&lt;/p&gt;

&lt;p&gt;工具文化几乎是大平台互联网公司共有的特质，我们无法确定是工具文化驱动了Google、Facebook这类互联网公司的快速发展，还是快速发展的需要使其在内推广工具文化，但可以明确的是工具文化必不可少。在Facebook第二位中国籍工程师王淮的书中也提到提到：
当时招聘他进Facebook的总监黄易山，是对内部工具的最有力倡导者：&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;他极度建议，公司要把最好的人才放到工具开发那一块，因为工具做好了，可以达到事半功倍的效果，所有人的效率都可以得到提高，而不仅仅是工程师。
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;在腾讯，工具文化虽没有被明确指出，但大平台公司对工具化的坚持是一致的：凡是被不断重复的过程，将其工具化，绑定到自动化流程之中。技术产品也需要&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Don’t make me think&lt;/code&gt;的方式来推广最佳实践。总而言之：依靠工具，而不是经验。&lt;/p&gt;

&lt;h2 id=&quot;自动化流程&quot;&gt;自动化流程&lt;/h2&gt;

&lt;p&gt;任务工具化是自动化流程的基础，我想你已经听说过任务运行器Grunt。Grunt帮助开发者把任务单元建立连接，如代码编译Task执行完后执行检测Task，检测Task执行完后执行压缩Task。虽然Grunt是基于Node.js平台，但其定位是个通用任务管理器，通用往往意味着更高的学习与实施成本。专注于Web开发领域腾讯有Mod.js来实施前端自动化，通过Mod.js有效的简化Web开发自动化流程实施成本。&lt;/p&gt;

&lt;h2 id=&quot;实施modjs&quot;&gt;实施Mod.js&lt;/h2&gt;

&lt;p&gt;Mod.js并不是简单的任务运行器，其内置集成了Web前端开发常用的工具集，覆盖了80%的前端使用场景，而另外的20%则可通过Mod.js的插件机制来扩展。&lt;/p&gt;

&lt;h3 id=&quot;相遇&quot;&gt;相遇&lt;/h3&gt;

&lt;p&gt;Mod.js:&lt;a href=&quot;https://github.com/modjs/mod&quot;&gt;https://github.com/modjs/mod&lt;/a&gt; 可通过&lt;a href=&quot;https://npmjs.org/&quot;&gt;NPM&lt;/a&gt;来安装最新的版本, 在你来到&lt;a href=&quot;http://nodejs.org/&quot;&gt;Node.js&lt;/a&gt;的编程世界时已同时附带了NPM，当前Mod.js最新版本&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0.4.x&lt;/code&gt;要求Node.js要求&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;gt;= 0.8.0&lt;/code&gt;：&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;npm &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;modjs &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-g&lt;/code&gt; 参数表示把Mod.js安装到全局，如此&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mod&lt;/code&gt;命令将会在&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;system path&lt;/code&gt;内，方便在任何一个目录启动Mod.js任务。&lt;/p&gt;

&lt;h3 id=&quot;相识&quot;&gt;相识&lt;/h3&gt;

&lt;p&gt;Mod.js通过Modfile.js文件驱动任务执行，可以手动创建一个Modfile.js文件，也可以通过模版初始化一个Modfile.js文件：&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;mod init modfile
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Modfile.js是一个Plain Node Module, 通过 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Runner&lt;/code&gt; 对象来描述任务的具体执行过程：&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// 暴露Runner对象&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;如是异步配置，则可通过回调模式传递Runner对象：&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// 回调Runner对象&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;runner&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{};&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;runner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;借此一瞥通常&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Runner&lt;/code&gt;对象的全貌：&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;gt;=0.4.3&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;plugins&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;pngcompressor&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;mod-png-compressor&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;compress&lt;/span&gt;      &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;grunt-contrib-compress&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;tasks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;asset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;asset&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;online&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;online_dist&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;offline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;offline_dist&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;offlinePackage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/package.zip&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;rm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;online&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&quot;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;offline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&quot;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./js/**/*.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;search&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;@VERSION&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./package.json&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;version&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;*.html&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;online&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;rev&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;offline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;rev&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;cp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;./img/**&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;online&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/img/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;rev&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;offline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/img/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;rev&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;pngcompressor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;./img/**/*.png&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;compress&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;dist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;na&quot;&gt;archive&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&apos;&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;// includes files in path&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;files&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
                    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                        &lt;span class=&quot;na&quot;&gt;expand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                        &lt;span class=&quot;na&quot;&gt;cwd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                        &lt;span class=&quot;na&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;*.html&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
                        &lt;span class=&quot;na&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;qq.com/web&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;
                    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
                    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                        &lt;span class=&quot;na&quot;&gt;expand&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                        &lt;span class=&quot;na&quot;&gt;cwd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/img&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                        &lt;span class=&quot;na&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
                        &lt;span class=&quot;na&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;cdn.qq.com/img&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;

                    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;targets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;rm&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;pngcompressor&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;cp&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;offline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;compress:dist&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;version&lt;/code&gt; 描述依赖的Mod.js版本&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;plugins&lt;/code&gt; 描述依赖的插件，支持Mod.js插件与Grunt插件&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tasks&lt;/code&gt;   描述不同类别任务的执行&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;targets&lt;/code&gt; 描述不同组合的目标，目标是需执行任务的集合&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mod.js的配置项追究极简易懂，即使不懂JavaScript语法也能看懂配置与修改配置。&lt;/p&gt;

&lt;h3 id=&quot;相知&quot;&gt;相知&lt;/h3&gt;

&lt;p&gt;在执行mod命令时，Mod.js会在当前目录下查找是否存在Modfile.js文件。当找到Modfile.js文件时，Mod.js将读取Modfile.js里的配置信息，如识别到有配置Mod.js插件，会自动安装没有安装过的插件，插件不仅可以是发布到NPM的包，也可以是存在本地的自定义任务。
Mod.js加载插件的方式是通过Node的require机制，然后执行暴露的exports.run，这与Mod.js内置任务的完全一样的机制。&lt;/p&gt;

&lt;p&gt;在命令行下，通常执行mod时是需指定Modfile.js中某一特定目标，但当存在命名为default的目标或配置中只有一个独立目标时，此时目标的指定是可选的，Mod.js会自动识别唯一的存在或default的目标：&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;targets: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    dist: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;rm&quot;&lt;/span&gt;, &lt;span class=&quot;s2&quot;&gt;&quot;cp&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 等价于 mod dist&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;mod
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;配置有default目标的场景：&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;targets: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    default: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;rm&quot;&lt;/span&gt;, &lt;span class=&quot;s2&quot;&gt;&quot;cp&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;,
    other: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;compress&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 等价于 mod default&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;mod
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;深入任务&quot;&gt;深入任务&lt;/h4&gt;

&lt;p&gt;任务是具体执行的类别，从配置示例开始阐述：&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;tasks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;./js/*.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;以上配置了一个文件压缩的&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;min&lt;/code&gt;类别任务，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src&lt;/code&gt;描述需要压缩的文件：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;js&lt;/code&gt;目录的所有js文件。&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src&lt;/code&gt;支持unix &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;glob&lt;/code&gt;语法来描述输入文件集，其匹配规则如下：&lt;/p&gt;

&lt;p&gt;匹配符：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;“*” 匹配0个或多个字符&lt;/li&gt;
  &lt;li&gt;”?” 匹配单个字符&lt;/li&gt;
  &lt;li&gt;“！” 匹配除此之外的字符&lt;/li&gt;
  &lt;li&gt;”[]” 匹配指定范围内的字符，如：[0-9]匹配数字0-9 [a-z]配置字母a-z&lt;/li&gt;
  &lt;li&gt;“{x,y}” 匹配指定组中某项，如 a{d,c,b}e 匹配 ade ace abe&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;示例：&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;c/ab.min.js &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;  c/ab.min.js
&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;.js        &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;  a.js b.js c.js
c/a&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;.js     &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;  c/a.js  c/ab.js c/ab.min.js
c/[a-z].js  &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;  c/a.js c/b.js c/c.js
c/[!abe].js &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;  c/c.js c/d.js
c/a?.js     &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;  c/ab.js c/ac.js
c/ab???.js  &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;  c/abdef.js c/abccc.js
c/[bdz].js  &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;  c/b.js c/d.js c/z.js
&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;a,b,c&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;.js  &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;  a.js b.js c.js
a&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;b,c&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;d,e&lt;span class=&quot;o&quot;&gt;}}&lt;/span&gt;x&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;y,z&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;.js  &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; abxy.js abxz.js  acdxy.js acdxz.js acexy.js acexz.js
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;更多任务配置规则深入:&lt;a href=&quot;https://github.com/modjs/mod/blob/master/doc/tutorial/configuring-tasks.md&quot;&gt;https://github.com/modjs/mod/blob/master/doc/tutorial/configuring-tasks.md&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;如任务没有配置&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dest&lt;/code&gt;，默认在输入文件同级目录下输出&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.min&lt;/code&gt;后缀的文件：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;uglifyjs Minifying ./js/unminify.js -&amp;gt; js/unminify.min.js
uglifyjs Original size: 1,393. Minified size: 449. Savings: 944 (210.24%)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;内置的&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;min&lt;/code&gt;任务支持三种文件类别的压缩，JavaScript、CSS与HTML，是对&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uglifyjs&lt;/code&gt;、&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cleancss&lt;/code&gt;与&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;htmlminfier&lt;/code&gt;任务的代理。&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;min&lt;/code&gt;通过识别文件后缀进行具体任务的分发。所以&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;min&lt;/code&gt;任务的&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src&lt;/code&gt;选项需指定具体的后缀。通常每个不同类别的任务都支持&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src&lt;/code&gt;与&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dest&lt;/code&gt;，且Mod.js会结合实际项目中常见的场景，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dest&lt;/code&gt;往往都是可选的，如上&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;min&lt;/code&gt;任务默认的&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dest&lt;/code&gt;是在当前目录下输出待&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.min&lt;/code&gt;后缀的文件，同时后缀名是支持通常&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;suffix&lt;/code&gt;选项配置的。&lt;/p&gt;

&lt;p&gt;每个内置任务支持的所有参数选项可通过&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Mod.js&lt;/code&gt;的在线文档查看：&lt;a href=&quot;https://github.com/modjs/mod/tree/master/doc&quot;&gt;https://github.com/modjs/mod/tree/master/doc&lt;/a&gt;
同时有丰富的演示项目来辅助不同任务的配置：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/modjs/mod/tree/master/example/catjs&quot;&gt;合并JS文件&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/modjs/mod/tree/master/example/catcss&quot;&gt;合并CSS文件，自动合并import文件&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/modjs/mod/tree/master/example/compileamd&quot;&gt;AMD模块文件编译&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/modjs/mod/tree/master/example/compilecmd&quot;&gt;CMD模块文件编译&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/modjs/mod/tree/master/example/compilemultipage&quot;&gt;多页面项目中AMD模块编译&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/modjs/mod/tree/master/example/compilejs&quot;&gt;JS文件条件编译&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/modjs/mod/tree/master/example/compilecss&quot;&gt;CSS文件条件编译&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/modjs/mod/tree/master/example/compilehtml&quot;&gt;HTML文件条件编译&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/modjs/mod/tree/master/example/minjs&quot;&gt;JS文件压缩&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/modjs/mod/tree/master/example/mincss&quot;&gt;CSS文件压缩&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/modjs/mod/tree/master/example/minhtml&quot;&gt;HTML文件压缩&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/modjs/mod/tree/master/example/stripcode&quot;&gt;代码移除，如alert、console&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/modjs/mod/tree/master/example/stripeol&quot;&gt;文件EOL移除&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/modjs/mod/tree/master/example/striptab&quot;&gt;文件Tab移除&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/modjs/mod/tree/master/example/datauri&quot;&gt;图片DataURI&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/modjs/mod/tree/master/example/mkdir&quot;&gt;创建目录&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/modjs/mod/tree/master/example/cp&quot;&gt;复制文件或目录&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/modjs/mod/tree/master/example/replace&quot;&gt;规则替换，如版本号累加&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;不可或缺的插件机制&quot;&gt;不可或缺的插件机制&lt;/h4&gt;

&lt;p&gt;Mod.js支持2种生态的插件：Mod.js 与 Grunt。插件的配置同样是在Runner对象下：&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;plugins&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Mod.js NPM 插件&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;sprite&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;mod-stylus&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Mod.js 本地插件&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;mytask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;./tasks/mytask&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Grunt NPM 插件&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;compress&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;grunt-contrib-compress&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;同样附上演示项目来辅助不同插件的配置：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/modjs/mod/tree/master/example/pluginnpmtask&quot;&gt;Mod.js NPM 插件: mod-stylus&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/modjs/mod/tree/master/example/pluginlocaltask&quot;&gt;Mod.js 本地插件: mytask.js&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/modjs/mod/tree/master/example/plugingrunttask&quot;&gt;Grunt NPM 插件: grunt-contrib-concat&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;如插件未安装在项目目录下或与Mod.js同级的全局目录下，Mod.js会自动通过NPM安装配置的插件。什么情况需要手动把插件安装在全局下？在实际项目开发中我们往往会对同一项目拉不同的分支进行开发，他们依赖的插件版本是相同的，此时如果在不同分支都安装一个冗余的插件版本项目是多余的，所以当你确定这是个插件是共享的，可以手动通过&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm install -g mod-stylus&lt;/code&gt;来安装到全局。同时项目目录中插件版本权重永远是高于全局的，如需避免加载全局的版本，只需手动在项目安装即可。&lt;/p&gt;

&lt;p&gt;限于篇幅，更多插件相关说明可访问以下主题页面：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/modjs/mod/tree/master/doc/tutorial/creating-plugins.md&quot;&gt;创建插件&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/modjs/mod/tree/master/doc/api&quot;&gt;API文档&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;零配置快速项目构建&quot;&gt;零配置快速项目构建&lt;/h4&gt;

&lt;p&gt;虽说是零配置构建项目，不如称之为基于DOM的项目构建，这个主题的内容与我之前在&lt;a href=&quot;https://github.com/AlloyTeam/Qing&quot;&gt;Qing&lt;/a&gt;项目中讨论的主题的一致的，在此只附上示例：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/modjs/mod/tree/master/example/buildnormal&quot;&gt;普通项目构建&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/modjs/mod/tree/master/example/buildmobile&quot;&gt;移动项目构建&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/modjs/mod/tree/master/example/buildrequirejs&quot;&gt;RequireJS项目构建&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;另外免配置文件对Sea.js 2.1+项目的支持正在开发中，会下Mod.js的下一迭代中支持。&lt;/p&gt;

&lt;h2 id=&quot;服务化&quot;&gt;服务化&lt;/h2&gt;

&lt;p&gt;了解完如何实施Mod.js进行自动化时，仅是停留在工具的层面，如何将其进一步的提升？了解一个事实，服务优于工具。如何将其封装成服务，用户无需安装Mod.js，无需执行命令，只需做一次事情：提交代码，中间的过程无需关注，最终把持续构建的结果反馈给用户。这是下一步需要去完善的，建立接入机制，让工具以服务的形式完全融入流程中。&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>ECMAScript6之模块系统</title>
   <link href="https://yuanyan.github.io/es6/modules"/>
   <updated>2013-09-15T00:00:00+00:00</updated>
   <id>hhttps://yuanyan.github.io/es6/modules</id>
   <content type="html">
&lt;h2 id=&quot;珊珊来迟&quot;&gt;珊珊来迟&lt;/h2&gt;
&lt;p&gt;也许是JavaScript降临于世的仓促性，注定其未来有许多改进空间。在编程语言的工程化上，JavaScript从孕育到诞生过程中也是少有甚至可以说是全无涉及，而模块化机制则是其中最严重的缺失，却是编程实践者们最迫切的需求（之一）。幸运的是，我们可以版本迭代，在ES6中终于开始着手制定语言的模块系统，珊珊来迟。&lt;/p&gt;

&lt;h2 id=&quot;术语&quot;&gt;术语&lt;/h2&gt;
&lt;p&gt;在介绍ES6模块系统之前，我们先了解一些基本的概念：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;module: 对代码单元的抽象，模块中可以 import 其他模块，可以 export 公共接口。&lt;/li&gt;
  &lt;li&gt;export: 模块可以暴露一些公共的方法或属性。&lt;/li&gt;
  &lt;li&gt;import: 通过模块名可以导入其他模块的公共接口。&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;语法&quot;&gt;语法&lt;/h2&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;import $ from &quot;jquery&quot;;                    // import the default export of a module
module crypto from &quot;crypto&quot;;               // binding an external module to a variable
import { encrypt, decrypt } from &quot;crypto&quot;; // binding a module&apos;s exports to variables
import { encrypt as enc } from &quot;crypto&quot;;   // binding and renaming one of a module&apos;s exports
export * from &quot;crypto&quot;;                    // re-exporting another module&apos;s exports
export { foo, bar } from &quot;crypto&quot;;         // re-exporting specified exports from another module
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;模块系统的工作机制&quot;&gt;模块系统的工作机制&lt;/h2&gt;

&lt;p&gt;介绍两个重要的类：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Module: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;new Module({ string: Object, ... }) -&amp;gt; Module&lt;/code&gt; 用来抽象模块的类。&lt;/li&gt;
  &lt;li&gt;Loader: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;new Loader(options = {}) -&amp;gt; Loader&lt;/code&gt; 用来定义如何获取源码、转化源码、最终把源码编译为模块实例的类。每个JavaScript运行环境（浏览器，Node.js）都会有一个默认的Loader实例来支持模块系统的运作。如在浏览器端默认的Loader实例为System。&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;如何兼容amd规范&quot;&gt;如何兼容AMD规范&lt;/h2&gt;

&lt;h2 id=&quot;如何兼容commonjs-modules规范&quot;&gt;如何兼容Common.JS Modules规范&lt;/h2&gt;

&lt;h2 id=&quot;refs&quot;&gt;Refs&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://wiki.ecmascript.org/doku.php?id=harmony:modules&quot;&gt;http://wiki.ecmascript.org/doku.php?id=harmony:modules&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://gist.github.com/wycats/51c96e3adcdb3a68cbc3&quot;&gt;https://gist.github.com/wycats/51c96e3adcdb3a68cbc3&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://wiki.ecmascript.org/doku.php?id=harmony:module_loaders&quot;&gt;http://wiki.ecmascript.org/doku.php?id=harmony:module_loaders&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>浏览器DNS缓存</title>
   <link href="https://yuanyan.github.io/performance/browser-dns-cache"/>
   <updated>2013-09-05T00:00:00+00:00</updated>
   <id>hhttps://yuanyan.github.io/performance/browser-dns-cache</id>
   <content type="html">
&lt;p&gt;什么是DNS？简而言之是从域名(www.qq.com)解析为IP(183.60.15.153)的过程，详情可移步 &lt;a href=&quot;http://en.wikipedia.org/wiki/Dns&quot;&gt;wikipedia&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;这篇文章用以记录浏览器级别的DNS缓存策略：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Firefox 默认的DNS缓存时间是 60s, 可通过在&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;about:config&lt;/code&gt;中&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;network.dnsCacheExpiration&lt;/code&gt;配置来进行修改&lt;/li&gt;
  &lt;li&gt;IE 30 min&lt;/li&gt;
  &lt;li&gt;Opera 15-60s&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;ref&quot;&gt;Ref&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://dyn.com/blog/web-browser-dns-caching-bad-thing/&quot;&gt;Why Web Browser DNS Caching Can Be A Bad Thing&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;(http://kb.mozillazine.org/Network.dnsCacheExpiration)&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>数据压缩之哈夫曼编码</title>
   <link href="https://yuanyan.github.io/performance/huffman-coding"/>
   <updated>2013-09-02T00:00:00+00:00</updated>
   <id>hhttps://yuanyan.github.io/performance/huffman-coding</id>
   <content type="html">
&lt;p&gt;读SPDY协议服务器侧实现源码，SPDY在通道复用的基础上也对HTTP Header进行了压缩，压缩算法是使用知名的zlib deflate压缩。而Deflate同时使用了LZ77算法与哈夫曼编码，鄙人知道哈夫曼编码是大学数据结构必考内容之一，所以先只抛哈夫曼编码来复习下（此处可拍砖），工作场景中无直接使用再加上记忆力无过人之处，学而时习之，不亦说(yuè)乎？&lt;/p&gt;

&lt;p&gt;Google了一份来自宝岛台湾的&lt;a href=&quot;http://hsmaterial.moe.edu.tw/file/computer/7I05/class800/7I05/final/7i05_2_3/movies.swf&quot;&gt;Flash动画&lt;/a&gt;，简单易懂，方便复习。&lt;/p&gt;

&lt;h2 id=&quot;ref&quot;&gt;Ref&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.zlib.net/feldspar.html&quot;&gt;Zlib&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://src.chromium.org/viewvc/chrome/trunk/src/net/spdy/spdy_protocol.h&quot;&gt;spdy_protocol.h&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.eecis.udel.edu/~amer/PEL/poc/pdf/SPDY-Fan.pdf&quot;&gt;A Methodology to Derive SPDY’s Initial Dictionary for Zlib Compression&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>ECMAScript6之生成器函数</title>
   <link href="https://yuanyan.github.io/es6/generators"/>
   <updated>2013-07-21T00:00:00+00:00</updated>
   <id>hhttps://yuanyan.github.io/es6/generators</id>
   <content type="html">
&lt;p&gt;在ECMAScript6新增特性中，最受关注的莫过于生成器函数（Generators），生成器可以极大的改变异步编程的体验。&lt;/p&gt;

&lt;h2 id=&quot;什么是生成器函数&quot;&gt;什么是生成器函数?&lt;/h2&gt;

&lt;p&gt;生成器函数长啥样？先端出来瞧瞧：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;// notice: function* instead of function
function* foo() {
  yield 0;
  for (var i = 0; i &amp;lt; arguments.length; i++) {
	yield arguments[i];
  }
  return &quot;bar&quot;;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;与普通的函数不同，生成器函数 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;function&lt;/code&gt; 关键字后多了一个&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*&lt;/code&gt;标识符，并且在函数体内使用了&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yield&lt;/code&gt;关键字。
执行一个生成器将返回一个迭代器，迭代器可以被ES6中新增的&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;for...of...&lt;/code&gt;循环遍历执行：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;for (var n of foo()) {
	console.log(n);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;也可以通过迭代器的&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;next()&lt;/code&gt;方法逐一执行：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;var seq = foo(1, 2, 3);  // =&amp;gt; [object Generator]
seq.next(); // { value: 0, done: false }
seq.next(); // { value: 1, done: false }
seq.next(); // { value: 2, done: false }
seq.next(); // { value: 3, done: false }
seq.next(); // { value: &quot;bar&quot;, done: true }
seq.next();  // Error: Generator has already finished
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;当第一次调用迭代器的&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;next()&lt;/code&gt;方法时，生成器才开始执行生成器函数（而不是在&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foo()&lt;/code&gt;构造生成器时），然后直到遇到yield时则暂停执行（挂起），此时yield关键字的右值将作为此次&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;next()&lt;/code&gt;方法的返回值。&lt;/p&gt;

&lt;p&gt;之后每次调用生成器的&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;next()&lt;/code&gt;方法，生成器将从上次暂停执行的状态开始，继续执行生成器函数，直到再次遇到yield时暂停，同样的yield的右值将作为&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;next()&lt;/code&gt;方法的返回值。&lt;/p&gt;

&lt;p&gt;如此反复一直到当调用&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;next()&lt;/code&gt;方法时生成器函数全部执行结束（遇到return、执行到函数末尾、抛出异常），则这次next方法的将返回函数执行的结果，如例子中返回了字符串&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bar&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;当前生成器执行结束后，在此时如再次调用&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;next()&lt;/code&gt;方法将会抛出&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Error: Generator has already finished&lt;/code&gt;异常。&lt;/p&gt;

&lt;h2 id=&quot;解决什么问题&quot;&gt;解决什么问题？&lt;/h2&gt;

&lt;p&gt;回顾迭代器函数执行的过程，我们思考下迭代器到底解决什么问题？&lt;/p&gt;

&lt;p&gt;我们调用一个普通的函数时，一般是从函数的第一行代码开始执行，结束于return语句、异常或者函数结束（隐式的返回undefined）。一旦函数将控制权交还给调用者，就意味着全部结束。函数中做的所有工作以及保存在局部变量中的数据都将丢失。再次调用这个函数时，一切都将从头创建。&lt;/p&gt;

&lt;p&gt;对于在计算机编程中所讨论的函数，这是很标准的流程。这样的函数只能返回一个值，不过，有时可以创建能产生一个序列的函数还是有帮助的。要做到这一点，这种函数需要能够“保存自己的工作“。&lt;/p&gt;

&lt;p&gt;我说过，能够“产生一个序列”是因为我们的函数并没有像通常意义那样返回。return隐含的意思是函数正将执行代码的控制权返回给函数被调用的地方。而”yield”的隐含意思是控制权的转移是临时和自愿的，我们的函数将来还会收回控制权。&lt;/p&gt;

&lt;p&gt;而拥有这种能力的“函数”被称为生成器，它非常的有用。生成器（以及yield语句）最初的引入是为了让程序员可以更简单的编写用来产生值的序列的代码。 以前，要实现类似随机数生成器的东西，需要实现一个类或者一个模块，在生成数据的同时保持对每次调用之间状态的跟踪。引入生成器之后，这变得非常简单。&lt;/p&gt;

&lt;h2 id=&quot;平台实现情况&quot;&gt;平台实现情况&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Node v0.11.2+ （需加上–harmony参数）&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;refs&quot;&gt;Refs&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;http://wiki.ecmascript.org/doku.php?id=harmony:generators&lt;/li&gt;
  &lt;li&gt;http://www.oschina.net/translate/improve-your-python-yield-and-generators-explained&lt;/li&gt;
  &lt;li&gt;http://tobyho.com/2013/06/16/what-are-generators/&lt;/li&gt;
  &lt;li&gt;http://callbackhell.com/&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>ECMAScript6之箭向函数</title>
   <link href="https://yuanyan.github.io/es6/arrow-functions"/>
   <updated>2013-07-20T00:00:00+00:00</updated>
   <id>hhttps://yuanyan.github.io/es6/arrow-functions</id>
   <content type="html">
&lt;h2 id=&quot;什么是箭向函数&quot;&gt;什么是箭向函数?&lt;/h2&gt;

&lt;p&gt;举个例子：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;var arr = [1,2,3,4,5];
var total = arr.reduce(function(x,y){ return x+y});
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;例子中是对数组进行求和，reduce方法需传入一个函数，我们使用function关键字声明一个匿名函数，并返回x+y的结果。
然使用箭向函数语法，我们可以如何简化？&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;var arr = [1,2,3,4,5];
var total = arr.reduce((x,y)=&amp;gt;x+y);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;可以认为箭向函数声明是普通函数声明的语法糖，其格式如下：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; () =&amp;gt; { ... }     // 无参数
 x =&amp;gt; { ... }      // 单个参数
 (x, y) =&amp;gt; { ... } // 多个参数
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;如果需要返回的是字面量对象则需要用括号 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;( ... )&lt;/code&gt; 包裹起来：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;val =&amp;gt; ({key: val})
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;绑定词法的this&quot;&gt;绑定词法的this&lt;/h2&gt;

&lt;p&gt;什么是词法绑定？上例子：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;var counter1 = {
    cur : 0,
    inc: () =&amp;gt; ++this.cur
}
counter1.inc() // -&amp;gt; NaN

var counter2 = {
    cur : 0,
    inc: function(){ return ++this.cur }
}
counter2.inc() // -&amp;gt; 1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;我们看到例子中counter1虽然是通过箭向函数简化了输入，但最后输出的结果多少会有些不解，为什么呢？答案就是本节的标题，箭向函数中的this是词法绑定的。&lt;/p&gt;

&lt;p&gt;因为创建一个箭向函数实际等同于先创建一个匿名函数，然后再创建给匿名函数绑定当前this的函数：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;() =&amp;gt; ++this.cur
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;等同于&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;function(){ return ++this.cur }.bind(this)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;所以箭向函数的的this即使通过bind也是无法改变的，因为其已经被bind了当前词法的this，所以在例子中this指向的是root对象，浏览器中则是window对象。
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;this.cu&lt;/code&gt;r 为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;undefined&lt;/code&gt;，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;++this.cur&lt;/code&gt;则返回&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NaN&lt;/code&gt;。&lt;/p&gt;

&lt;h2 id=&quot;貌似用标准的函数声明也能解决问题为什么要用箭向函数呢&quot;&gt;貌似用标准的函数声明也能解决问题，为什么要用箭向函数呢？&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;想想为什么我们更喜欢使用字面量声明而不是 new String 或 new Array 呢？ 简洁明了呗&lt;/li&gt;
  &lt;li&gt;总是会返回末尾的执行结果，像 reduce map 常用的计算数组的操作往往都需要返回值&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;在以往的经验中我们往往会像下面例子中那样在另一回调函数中通过that变量来帮助引用到外层函数的this&lt;/p&gt;

    &lt;p&gt;var yuanyan = {
     name: “yuanyan”,
     sayHi: function () {
         var that = this;
         setTimeout(function () {
             console.log(that.name + “ says hi”)
         })
     }
 }&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;而通过箭向函数则无需再使用that，因其绑定了词法的this：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;var yuanyan = {
    name: &quot;yuanyan&quot;,
    sayHi: function () {
        setTimeout( () =&amp;gt; console.log(this.name + &quot; says hi&quot;),100)
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;已支持的浏览器&quot;&gt;已支持的浏览器&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Firefox 22.0 +&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;为什么把-arrow-functions-翻译为箭向函数而不是更字面意的箭头函数&quot;&gt;为什么把 Arrow Functions 翻译为箭向函数而不是更字面意的箭头函数？&lt;/h2&gt;
&lt;p&gt;原因是为了区分两种不一样的箭头符号：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-&amp;gt;&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;=&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;称&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-&amp;gt;&lt;/code&gt;是箭头，而&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;=&amp;gt;&lt;/code&gt;是箭向，而Arrow Functions中目前只使用了&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;=&amp;gt;&lt;/code&gt;符号，所以这里称其为箭向函数。&lt;/p&gt;

&lt;h2 id=&quot;refs&quot;&gt;Refs&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://people.mozilla.org/~jorendorff/es6-draft.html#sec-13.2&quot;&gt;http://people.mozilla.org/~jorendorff/es6-draft.html#sec-13.2&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://wiki.ecmascript.org/doku.php?id=harmony:arrow_function_syntax&quot;&gt;http://wiki.ecmascript.org/doku.php?id=harmony:arrow_function_syntax&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/arrow_functions&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/arrow_functions&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.2ality.com/2012/04/arrow-functions.html&quot;&gt;http://www.2ality.com/2012/04/arrow-functions.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>浏览器连接数方案</title>
   <link href="https://yuanyan.github.io/solution/browser-connections-solution"/>
   <updated>2013-06-19T00:00:00+00:00</updated>
   <id>hhttps://yuanyan.github.io/solution/browser-connections-solution</id>
   <content type="html">
&lt;p&gt;这个主题源于taobao的一个活动页面，看图说话：
&lt;img src=&quot;http://ww3.sinaimg.cn/mw1024/6b29bb61gw1e5scyc97sfj20pn0b9mzu.jpg&quot; alt=&quot;weiboimg&quot; /&gt;
这里的问题是没有把图切细，解决的方案也很自然，多切几张图，每张图的大小控制在30-50K以内。&lt;/p&gt;

&lt;p&gt;但这时有童鞋可能会困惑一个问题，IE下的连接数问题如何解决？
回答这个问题之前我们先严谨的看下IE不同版本对连接数的限制：&lt;/p&gt;

&lt;table&gt;
    &lt;tbody&gt;&lt;tr&gt;&lt;th&gt;版本&lt;/th&gt;&lt;th&gt;HTTP 1.0 服务器（宽带连接）&lt;/th&gt;&lt;th&gt;HTTP 1.1 服务器（宽带连接）&lt;/th&gt;&lt;th&gt;HTTP 1.0 服务器（拨号连接）&lt;/th&gt;&lt;th&gt;HTTP 1.1 服务器（拨号连接）&lt;/th&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td&gt;Internet Explorer 7 和早期版本&lt;/td&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td&gt;Internet Explorer 8&lt;/td&gt;&lt;td&gt;6&lt;/td&gt;&lt;td&gt;6&lt;/td&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td&gt;Internet Explorer 9&lt;/td&gt;&lt;td&gt;10&lt;/td&gt;&lt;td&gt;10&lt;/td&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;如需考虑IE浏览器用户，如何突破限制? 让用户修改系统连接数配置，显然不合适。
可取的方案是什么？CDN绑定多域名，考虑IE版本中最低的连接数，每个域下控制只链接2个静态资源即可：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cdn1.qq.com
cdn2.qq.com
cdn3.qq.com
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;ref&quot;&gt;Ref&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://msdn.microsoft.com/zh-cn/library/cc304129(v=vs.85).aspx&quot;&gt;Internet Explorer 8 中的连接增强功能&lt;/a&gt;
&lt;a href=&quot;http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html#sec8.1.4&quot;&gt;HTTP 1.1 规范中最大连接数目设置为2的强制性要求&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>QQ登录项目前端优化小记</title>
   <link href="https://yuanyan.github.io/performance/qqlogin-performance-optimization"/>
   <updated>2013-06-13T00:00:00+00:00</updated>
   <id>hhttps://yuanyan.github.io/performance/qqlogin-performance-optimization</id>
   <content type="html">
&lt;h4 id=&quot;小记各点此文不展开&quot;&gt;小记各点，此文不展开&lt;/h4&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;1. 移除QFZL, 告别历史遗留因素的束缚
2. 关键业务代码内嵌
3. 更多是使用CSS3动画代替JS动画
4. 合理的模块化开发
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;未完待续…&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>前端执行性能</title>
   <link href="https://yuanyan.github.io/performance/front-end-execution-performance"/>
   <updated>2013-06-13T00:00:00+00:00</updated>
   <id>hhttps://yuanyan.github.io/performance/front-end-execution-performance</id>
   <content type="html">
&lt;p&gt;Web前端性能通常可划为两个主题，一部分是加载性能，另一部分是执行性能。&lt;/p&gt;

&lt;p&gt;未完待续…&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>高性能移动Web前端</title>
   <link href="https://yuanyan.github.io/performance/high-performance-mobile-frontend"/>
   <updated>2013-06-06T00:00:00+00:00</updated>
   <id>hhttps://yuanyan.github.io/performance/high-performance-mobile-frontend</id>
   <content type="html">
&lt;p&gt;高性能移动Web相较PC的场景需要考虑的因素也相对更多更复杂，我们总结为以下几点： 流量、功耗与流畅度。
在PC时代我们更多的是考虑体验上的流畅度，而在Mobile端本身丰富的场景下，需要额外关注对用户基站网络流量使用的情况，设备耗电量的情况。&lt;/p&gt;

&lt;p&gt;关于流畅度，主要体现在前端动画中，人在前端动画体系中，通常有两种模式：JS动画与CSS动画。
JS动画是为在低级浏览器中实现动画能力的一种方案，而在移动端，我们必然选择CSS动画。&lt;/p&gt;

&lt;p&gt;然而在移动端，CSS动画相比PC会面对更多的性能问题，主要体现在动画的卡顿与闪烁。&lt;/p&gt;

&lt;p&gt;目前对提升移动端CSS动画体验的主要方法有几点：&lt;/p&gt;

&lt;h4 id=&quot;尽可能多的利用硬件能力如使用3d变形来开启gpu加速&quot;&gt;尽可能多的利用硬件能力，如使用3D变形来开启GPU加速。&lt;/h4&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;-webkit-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0);
-ms-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;如动画过程有闪烁（通常发生在动画开始的时候），可以尝试下面的Hack：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;-webkit-backface-visibility: hidden;
-moz-backface-visibility: hidden;
-ms-backface-visibility: hidden;
backface-visibility: hidden;

-webkit-perspective: 1000;
-moz-perspective: 1000;
-ms-perspective: 1000;
perspective: 1000;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;如下面一个元素通过translate3d右移500px的动画流畅度会明显优于使用left属性：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#ball-1 {
  transition: -webkit-transform .5s ease;
  -webkit-transform: translate3d(0, 0, 0);
}
#ball-1.slidein {
  -webkit-transform: translate3d(500px, 0, 0);
}


#ball-2 {
  transition: left .5s ease;
  left：0;
}
#ball-2.slidein {
  left：500px;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;注：3D变形会消耗更多的内存与功耗，应确实有性能问题时才去使用它，兼在权衡&lt;/p&gt;

&lt;h4 id=&quot;尽可能少的使用box-shadows与gradients&quot;&gt;尽可能少的使用box-shadows与gradients&lt;/h4&gt;

&lt;p&gt;box-shadows与gradients往往都是页面的性能杀手，尤其是在一个元素同时都使用了它们。&lt;/p&gt;

&lt;h4 id=&quot;尽可能的让动画元素不在文档流中以减少重排&quot;&gt;尽可能的让动画元素不在文档流中，以减少重排&lt;/h4&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;position: fixed;
position: absolute;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;持续更新中…&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>QQ查找项目前端优化小记</title>
   <link href="https://yuanyan.github.io/performance/qqfind-performance-optimization"/>
   <updated>2013-06-01T00:00:00+00:00</updated>
   <id>hhttps://yuanyan.github.io/performance/qqfind-performance-optimization</id>
   <content type="html">
&lt;p&gt;以上案例皆为外相，正本清源，关注Web加载过程中4个关键时间点：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;1. Time to First Byte              服务端返回时间
2. Time to Start Render         白屏结束时间
3. Time to Interactive            用户可交互时间
4. Time to Document Ready     文档加载完成时间
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;而优化过程大多围绕关键点展开，方式大致可归为以下4类：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;1. 减少请求 -    合并文件、更多的使用CSS代替图片、内嵌小型文件
2. 加快响应   -  DNS预解析、接入机多地部署、SPDY/HTTP2.0、资源CDN部署、压缩HTML、压缩CSS、压缩JS、压缩图片
3. 并行加载请求 -  拆分大型文件
4. 预加载请求 - HEAD中请求初始数据、HTML5 prefetch/prerender
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;结束语本是已被说烂的金庸句式：“天下武功唯快不破”，想想不能落入俗套呀。大脑闪过 Facebook 在早期的一句话“Move Fast and break things”，
然而当我们面向海量用户时，更可取方式应该是“Move Fast and monitor closely“，在快速的产品迭代过程中进行即时的监控，而性能数据是监控系统中重要的环节之一。
而如何在自动化发布构建流程上保证外发版本的性能，是需要一直努力的方向一直。&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;抱歉，暂不公布案例
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</content>
 </entry>
 
 <entry>
   <title>小议 SVG 与 Canvas</title>
   <link href="https://yuanyan.github.io/solution/svg-and-canvas"/>
   <updated>2013-06-01T00:00:00+00:00</updated>
   <id>hhttps://yuanyan.github.io/solution/svg-and-canvas</id>
   <content type="html">
&lt;p&gt;canvas是h5体系集中的一种基于像素操作的图形技术，svg同样也是h5中一部分，只是svg基于矢量形状，两者有各种的优势。
以下数据来自微软童鞋的测试，传送门： http://msdn.microsoft.com/zh-cn/library/ie/gg193983(v=vs.85).aspx：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;图面较小时、对象数量较大 (&amp;gt;10k)（或同时满足这二者）时 canvas 性能更佳;
对象数量较小 (&amp;lt;10k)、图面更大（或同时满足这二者）时 svg 性能更佳;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;关于对canvas进行频繁操作，性能真的就会比svg好吗？&lt;/p&gt;

&lt;p&gt;关键是操作姿势与场景，在没有前置条件的结论往往是片面的，只举一个例子，我们操作一个图形，对canvas的操作以常用的清屏方式(不是脏矩形姿势)，然后进行频繁操作，
对比svg，svg的渲染显然经过浏览器的优化，只会进行部分区域的重绘，而canvas则需重绘整个画片，可想而知在此常见场景中，svg会显的更有优势，canvas应该更适合游戏编程。&lt;/p&gt;

&lt;p&gt;未完待续…&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>前端模版的奋斗史</title>
   <link href="https://yuanyan.github.io/solution/templating-solution"/>
   <updated>2013-04-17T00:00:00+00:00</updated>
   <id>hhttps://yuanyan.github.io/solution/templating-solution</id>
   <content type="html">
&lt;h3 id=&quot;为什么需要模版&quot;&gt;为什么需要模版？&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;var html = &quot;&amp;lt;ul class=&apos;&quot; + myClass + &quot;&apos;&amp;gt;&quot; +
    &quot;&amp;lt;li id=&apos;&quot; + myId + &quot;&apos;&amp;gt;&quot; + myContents + &quot;&amp;lt;/li&amp;gt;&quot;;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;如上示例，我想没人愿意做字符串拼接的工作，易出错且维护性极低，需避免以上坏味道代码出现在你的程序中。&lt;/p&gt;

&lt;p&gt;模版是解耦视图的有效手段，我们通过模版引擎把数据与模版渲染后的结果呈现给用户，这渲染过程说白了就是把字符串的拼接工作交由模版引擎。&lt;/p&gt;

&lt;p&gt;在不同的开发模式下模版渲染发生的端是不同的，这里的端分为两种：服务器与客户端。&lt;/p&gt;

&lt;p&gt;在CGI吐HTML片断数据的开发模式下，模版的渲染是在服务器端进行，客户端发起一个请求，服务器把渲染后的结果推送到客户端，前端获取到HTML片断后直接将其插入到DOM中。
但如此有几个问题，首先，CGI无法适应多终端不同视图的场景；其次，在移动端，网络带宽依旧是瓶颈之一。
所以在现代Web开发需求下，CGI只吐JSON数据，区别与服务端渲染数据的模式，开始将数据的渲染放在客户端进行。&lt;/p&gt;

&lt;p&gt;而在Web浏览器中承担模版渲染的工作则交由了编程界的屌丝Javascript。&lt;/p&gt;

&lt;h3 id=&quot;简易模版引擎实现&quot;&gt;简易模版引擎实现&lt;/h3&gt;

&lt;p&gt;模版引擎的实现主要有两种思路：一种是通过纯粹的正则匹配，另一种是词法分析与语法解析。任何一种模版语法都可以用这两种不同的思路来实现。
我们用第一种正则的方式来实现一个简易的模版引擎：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/**
 * Function: template
 * 简单的模板机制
 *
 * Parameters:
 *  tmpl - {String} 模板
 *  val - {Object} 模板对象
 *
 * Returns:
 * {String}
 */
var template = function(tmpl, val){

    return tmpl.replace(/\$\{(\w+)\}/g, function(m, i){
        if (val[i]) {
            return val[i];
        }
        else { // 模板对象未定义时
            return &quot;&quot;;
        }
    });
};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;整个实现基于字符串的replace机制, 实现了模版变量的替换功能：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;var tmpl = &quot;${a},${b},${c}&quot;
var res = template(tmpl, { a: &apos;a&apos;, b: &apos;b&apos;})    // a,b,
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;未完待续…&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>重新审视那位优雅的CSS</title>
   <link href="https://yuanyan.github.io/css3/how-css-instead-of-javascript"/>
   <updated>2013-03-21T00:00:00+00:00</updated>
   <id>hhttps://yuanyan.github.io/css3/how-css-instead-of-javascript</id>
   <content type="html">
&lt;p&gt;从一个盒中小鱼demo讲起：
&lt;a href=&quot;http://www.w3.org/Talks/2013/0128-CSS-Utrecht/demo-transforms/demo-translate3d-cube.html&quot;&gt;http://www.w3.org/Talks/2013/0128-CSS-Utrecht/demo-transforms/demo-translate3d-cube.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;demo的精彩之处在于没有用一行Javascript代码便实现了所有小鱼在盒子中漫游的行为，因其只使用CSS引擎默认的选择器机制。&lt;/p&gt;

&lt;p&gt;只用CSS实现动画的控制，这并不陌生，平时工作中也常用hover伪类来触发鼠标悬浮后的样式或行为，而不是去绑定mouse行为事件。
如tooltip中通过hover伪类选择器来控制tooltip的显示与隐藏，实现起来比Javascript方案优雅的多。&lt;/p&gt;

&lt;p&gt;但如何通过CSS来捕捉demo中的点击行为呢？&lt;/p&gt;

&lt;p&gt;从demo页面源码中截取如下真相：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#moveme {position: absolute; top: 50%; left: 50%; .... -webkit-transition: 1.5s}
#top-left:target #moveme {-webkit-transform: translate3d(-130px,-130px,300px)}
#top-right:target #moveme {-webkit-transform: translate3d(100px,-130px,150px)}
#bottom-left:target #moveme {-webkit-transform: translate3d(-100px,90px,300px)}
#bottom-right:target #moveme {-webkit-transform: translate3d(90px,90px,300px)}
#center:target #moveme {-webkit-transform: translate3d(-10px,40px,100px)}


&amp;lt;ul&amp;gt;
  &amp;lt;li&amp;gt;&amp;lt;a href=&quot;#&quot;&amp;gt;original&amp;lt;/a&amp;gt;
  &amp;lt;li&amp;gt;&amp;lt;a href=&quot;#center&quot;&amp;gt;center&amp;lt;/a&amp;gt; = translate3d(-10px,40px,100px)
  &amp;lt;li&amp;gt;&amp;lt;a href=&quot;#top-left&quot;&amp;gt;top left&amp;lt;/a&amp;gt; = translate3d(-130px,-130px,300px)
  &amp;lt;li&amp;gt;&amp;lt;a href=&quot;#top-right&quot;&amp;gt;top right&amp;lt;/a&amp;gt; = translate3d(100px,-130px,150px)
  &amp;lt;li&amp;gt;&amp;lt;a href=&quot;#bottom-left&quot;&amp;gt;bottom left&amp;lt;/a&amp;gt; = translate3d(-100px,90px,300px)
  &amp;lt;li&amp;gt;&amp;lt;a href=&quot;#bottom-right&quot;&amp;gt;bottom right&amp;lt;/a&amp;gt; = translate3d(90px,90px,300px)
&amp;lt;/ul&amp;gt;

&amp;lt;em id=moveme&amp;gt;&amp;lt;/em&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;代码中的关键是 :target 伪类选择器。 看 MDN 中是如何描述 ：target 的？ &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/CSS/:target&quot;&gt;https://developer.mozilla.org/en-US/docs/CSS/:target&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;The :target pseudo-class represents the unique element, if any, with an id matching the fragment identifier of the URI of the document..

URIs with fragment identifiers link to a certain element within the document, known as the target element. For instance, here is a URI pointing to an anchor named section2:
  http://example.com/folder/document.html#section2
The anchor can be any element with an id attribute, e.g. &amp;lt;h1 id=&quot;section2&quot;&amp;gt; in our example. The target element h1 can be represented by the :target pseudo-class.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;MDN 中也提供了关于 :target 伪类选择器的一种应用&lt;a href=&quot;https://mdn.mozillademos.org/files/4607/lightbox.html&quot;&gt;https://mdn.mozillademos.org/files/4607/lightbox.html&lt;/a&gt;，只用CSS实现了lightbox的组件。&lt;/p&gt;

&lt;p&gt;前端童鞋应考虑如何尽量只用CSS来控制前端视图层的交互行为，JS在前端虽是无所不能的，但与CSS相比，无论是维护性与优雅度都无法企及CSS的实现方案。
让各自的职责明确也是前端的架构的要点，CSS与JS各司其职，别老想用JS来解决一切问题。&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>P3P 方案</title>
   <link href="https://yuanyan.github.io/solution/p3p-solution"/>
   <updated>2013-03-04T00:00:00+00:00</updated>
   <id>hhttps://yuanyan.github.io/solution/p3p-solution</id>
   <content type="html">
&lt;p&gt;科普，什么是P3P？ 全称是 Platform for Privacy Preferences (P3P) Project， 即为保护网络隐私相关的标准 (http://www.w3.org/P3P/) ,
现常用于指代由此导致的跨源内嵌页无法访问cookie的问题。&lt;/p&gt;

&lt;h3 id=&quot;p3p-头方案&quot;&gt;P3P 头方案&lt;/h3&gt;

&lt;p&gt;大部分浏览器（IE），设置 P3P 头即可解决iframe页设置cookie的问题：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;P3P: CP=HONK
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;表单方案&quot;&gt;表单方案&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;var cookieForm = document.createElement(&quot;form&quot;);
cookieForm.action = &quot;A.com/setCookie?cache=1231213123&quot;;
cookieForm.method = &quot;post&quot;;
document.body.appendChild(cookieForm);



var name = &apos;test_cookie&apos;;

var iframe = document.createElement(&apos;iframe&apos;);
iframe.name = name;
iframe.src = &apos;javascript:false&apos;;
document.appendChild(iframe);

var form = document.createElement(&apos;form&apos;);
form.action = location.toString();
form.method = &apos;POST&apos;;
form.target = name;
document.appendChild(form);
form.submit();
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;documentdomain方案&quot;&gt;document.domain方案&lt;/h3&gt;

&lt;p&gt;在腾讯，部门间协作更多是跨子域名问题，这是最好的情况，解决起来也非常轻松。如主页是 a.qq.com，内嵌iframe页是 b.qq.com，此时分别设置两页面的 document.domain = ‘qq.com’ 即可。&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>DOM layout 性能</title>
   <link href="https://yuanyan.github.io/performance/dom-layout-performance"/>
   <updated>2013-02-05T00:00:00+00:00</updated>
   <id>hhttps://yuanyan.github.io/performance/dom-layout-performance</id>
   <content type="html">
&lt;p&gt;我们从两断代码开始今天的话题：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;var newWidth = aDiv.offsetWidth + 10;
aDiv.style.width = newWidth + &apos;px&apos;;
var newHeight = aDiv.offsetHeight + 10;
aDiv.style.height = newHeight + &apos;px&apos;;

var newWidth = aDiv.offsetWidth + 10;
var newHeight = aDiv.offsetHeight + 10;
aDiv.style.width = newWidth + &apos;px&apos;;
aDiv.style.height = newHeight + &apos;px&apos;;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;这是两段能力上完全等同的代码，显式的差异正如我们所见，只有执行顺序的区别。但真是如此吗？下面是加了说明注释的代码版本，很好的阐述了其中的进一步差异：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;// 触发两次 layout
var newWidth = aDiv.offsetWidth + 10;   // Read
aDiv.style.width = newWidth + &apos;px&apos;;     // Write
var newHeight = aDiv.offsetHeight + 10; // Read
aDiv.style.height = newHeight + &apos;px&apos;;   // Write

// 只触发一次 layout
var newWidth = aDiv.offsetWidth + 10;   // Read
var newHeight = aDiv.offsetHeight + 10; // Read
aDiv.style.width = newWidth + &apos;px&apos;;     // Write
aDiv.style.height = newHeight + &apos;px&apos;;   // Write
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;从注释中可找到规律，连续的读取offsetWidth/Height属性与连续的设置width/height属性，相比分别读取设置单个属性可少触发一次layout。&lt;/p&gt;

&lt;p&gt;从结论看似乎与执行队列有关，没错，这是浏览器的优化策略。所有可触发layout的操作都会被暂时放入 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;layout-queue&lt;/code&gt; 中，等到必须更新的时候，再计算整个队列中所有操作影响的结果，如此就可只进行一次的layout，从而提升性能。&lt;/p&gt;

&lt;p&gt;关键一，可触发layout的操作，哪些操作下会layout的更新（也称为reflow或者relayout）？&lt;/p&gt;

&lt;p&gt;我们从浏览器的源码实现入手，以开源&lt;a href=&quot;https://code.google.com/p/chromium/codesearch#chromium/src/third_party/WebKit/Source/core/&quot;&gt;Webkit/Blink&lt;/a&gt;为例，
对layout的更新，Webkit 主要通过 &lt;a href=&quot;https://code.google.com/p/chromium/codesearch#chromium/src/third_party/WebKit/Source/core/dom/Document.cpp&amp;amp;q=updateLayout%20package:%5Echromium$%20file:%5Esrc/third_party/WebKit/Source/core/&amp;amp;dr=CSs&amp;amp;l=1715&quot;&gt;Document::updateLayout&lt;/a&gt;
与 &lt;a href=&quot;https://code.google.com/p/chromium/codesearch#chromium/src/third_party/WebKit/Source/core/dom/Document.cpp&amp;amp;q=updateLayout%20package:%5Echromium$%20file:%5Esrc/third_party/WebKit/Source/core/&amp;amp;dr=CSs&amp;amp;l=1750&quot;&gt;Document::updateLayoutIgnorePendingStylesheets&lt;/a&gt;
两个方法：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;void Document::updateLayout()
{
    ASSERT(isMainThread());

    FrameView* frameView = view();
    if (frameView &amp;amp;&amp;amp; frameView-&amp;gt;isInLayout()) {
        ASSERT_NOT_REACHED();
        return;
    }

    if (Element* oe = ownerElement())
        oe-&amp;gt;document()-&amp;gt;updateLayout();

    updateStyleIfNeeded();

    StackStats::LayoutCheckPoint layoutCheckPoint;

    if (frameView &amp;amp;&amp;amp; renderer() &amp;amp;&amp;amp; (frameView-&amp;gt;layoutPending() || renderer()-&amp;gt;needsLayout()))
        frameView-&amp;gt;layout();

    if (m_focusedNode &amp;amp;&amp;amp; !m_didPostCheckFocusedNodeTask) {
        postTask(CheckFocusedNodeTask::create());
        m_didPostCheckFocusedNodeTask = true;
    }
}


void Document::updateLayoutIgnorePendingStylesheets()
{
    bool oldIgnore = m_ignorePendingStylesheets;

    if (!haveStylesheetsLoaded()) {
        m_ignorePendingStylesheets = true;

        HTMLElement* bodyElement = body();
        if (bodyElement &amp;amp;&amp;amp; !bodyElement-&amp;gt;renderer() &amp;amp;&amp;amp; m_pendingSheetLayout == NoLayoutWithPendingSheets) {
            m_pendingSheetLayout = DidLayoutWithPendingSheets;
            styleResolverChanged(RecalcStyleImmediately);
        } else if (m_hasNodesWithPlaceholderStyle)
            recalcStyle(Force);
    }

    updateLayout();

    m_ignorePendingStylesheets = oldIgnore;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;从 updateLayoutIgnorePendingStylesheets 方法的内部实现可知，其也是对 updateLayout 方法的扩展，并且在现有的 layout 更新模式中，大部分场景都是调用 updateLayoutIgnorePendingStylesheets 来进行layout的更新。&lt;/p&gt;

&lt;p&gt;搜索 Webkit 实现中调用 &lt;a href=&quot;https://code.google.com/p/chromium/codesearch#search/&amp;amp;q=updateLayoutIgnorePendingStylesheets&amp;amp;sq=package:chromium&amp;amp;type=cs&quot;&gt;updateLayoutIgnorePendingStylesheets&lt;/a&gt; 方法的代码,
得到以下可导致触发 layout 的操作：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Element&lt;/code&gt;:
clientHeight, clientLeft, clientTop, clientWidth, focus(), getBoundingClientRect(), getClientRects(), innerText, offsetHeight, offsetLeft, offsetParent, offsetTop, offsetWidth, outerText, scrollByLines(), scrollByPages(), scrollHeight, scrollIntoView(), scrollIntoViewIfNeeded(), scrollLeft, scrollTop, scrollWidth&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Frame, HTMLImageElement&lt;/code&gt;:
height, width&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Range&lt;/code&gt;:
getBoundingClientRect(), getClientRects()&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SVGLocatable&lt;/code&gt;:
computeCTM(), getBBox()&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SVGTextContent&lt;/code&gt;:
getCharNumAtPosition(), getComputedTextLength(), getEndPositionOfChar(), getExtentOfChar(), getNumberOfChars(), getRotationOfChar(), getStartPositionOfChar(), getSubStringLength(), selectSubString()&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SVGUse&lt;/code&gt;:
instanceRoot&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;window&lt;/code&gt;:
getComputedStyle(), scrollBy(), scrollTo(), scrollX, scrollY, webkitConvertPointFromNodeToPage(), webkitConvertPointFromPageToNode()&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;进一步深入Layout，那上文中必须更新的必要条件是什么？
在 Stoyan Stefanov 的 &lt;a href=&quot;http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/&quot;&gt;Rendering: repaint, reflow/relayout, restyle&lt;/a&gt; 一文中已做比较详细的解答，可移步了解~&lt;/p&gt;

&lt;h2 id=&quot;ref&quot;&gt;Ref&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/&quot;&gt;Rendering: repaint, reflow/relayout, restyle&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://gent.ilcore.com/2011/03/how-not-to-trigger-layout-in-webkit.html&quot;&gt;How (not) to trigger a layout in WebKit&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>慎用 requestAnimationFrame</title>
   <link href="https://yuanyan.github.io/html5/use-raf-carefully"/>
   <updated>2012-10-25T00:00:00+00:00</updated>
   <id>hhttps://yuanyan.github.io/html5/use-raf-carefully</id>
   <content type="html">
&lt;p&gt;requestAnimationFrame 是什么？&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;http://paulirish.com/2011/requestanimationframe-for-smart-animating/&lt;/li&gt;
  &lt;li&gt;http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;一份对不同浏览器 requestAnimationFrame 实现规格化的polyfill：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;// requestAnimationFrame polyfill by Erik Möller
// fixes from Paul Irish and Tino Zijdel
(function() {
    var lastTime = 0;
    var vendors = [&apos;ms&apos;, &apos;moz&apos;, &apos;webkit&apos;, &apos;o&apos;];
    for(var x = 0; x &amp;lt; vendors.length &amp;amp;&amp;amp; !window.requestAnimationFrame; ++x) {
        window.requestAnimationFrame = window[vendors[x]+&apos;RequestAnimationFrame&apos;];
        window.cancelAnimationFrame = window[vendors[x]+&apos;CancelAnimationFrame&apos;]
                                   || window[vendors[x]+&apos;CancelRequestAnimationFrame&apos;];
    }

    if (!window.requestAnimationFrame)
        window.requestAnimationFrame = function(callback, element) {
            var currTime = new Date().getTime();
            var timeToCall = Math.max(0, 16 - (currTime - lastTime));
            var id = window.setTimeout(function() { callback(currTime + timeToCall); },
              timeToCall);
            lastTime = currTime + timeToCall;
            return id;
        };

    if (!window.cancelAnimationFrame)
        window.cancelAnimationFrame = function(id) {
            clearTimeout(id);
        };
}());
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;jQuery从1.6.0版本引入了requestAnimationFrame，但在1.6.3版本时又将其移除，并且至今到1.8.2版本仍未使用这一优化特性，其中的原因是否困惑了您？&lt;/p&gt;

&lt;p&gt;jQuery 1.6.2：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;if ( t() &amp;amp;&amp;amp; jQuery.timers.push(t) &amp;amp;&amp;amp; !timerId ) {
    // Use requestAnimationFrame instead of setInterval if available
    if ( requestAnimationFrame ) {
        timerId = true;
        raf = function() {
            // When timerId gets set to null at any point, this stops
            if ( timerId ) {
                requestAnimationFrame( raf );
                fx.tick();
            }
        };
        requestAnimationFrame( raf );
    } else {
        timerId = setInterval( fx.tick, fx.interval );
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;jQuery 1.6.3 中已移除：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;if ( t() &amp;amp;&amp;amp; jQuery.timers.push(t) &amp;amp;&amp;amp; !timerId ) {
    timerId = setInterval( fx.tick, fx.interval );
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://hacks.mozilla.org/2011/08/animating-with-javascript-from-setinterval-to-requestanimationframe/&quot;&gt;Animating with javascript: from setInterval to requestAnimationFrame&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://forum.jquery.com/topic/please-don-t-remove-requestanimationframe&quot;&gt;Please don’t remove requestAnimationFrame!&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://stackoverflow.com/questions/7999680/why-doesnt-jquery-use-requestanimationframe&quot;&gt;Why doesn’t jQuery use requestAnimationFrame?&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://jsfiddle.net/9RNzC/&quot;&gt;http://jsfiddle.net/9RNzC/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://bugs.jquery.com/ticket/9381&quot;&gt;http://bugs.jquery.com/ticket/9381&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://gist.github.com/1579671&quot;&gt;requestAnimationFrame polyfill&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>Can I use</title>
   <link href="https://yuanyan.github.io/html5/can-i-use"/>
   <updated>2012-09-27T00:00:00+00:00</updated>
   <id>hhttps://yuanyan.github.io/html5/can-i-use</id>
   <content type="html">
&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://caniuse.com/&quot;&gt;When can I use&lt;/a&gt; - Compatibility tables for support of HTML5, CSS3, SVG and more in desktop and mobile browsers.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://wufoo.com/html5//&quot;&gt;The Current State of HTML5 Forms&lt;/a&gt; - Browser support for the different features of HTML5 forms is quite varied. Let’s explore.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://www.quirksmode.org/html5/inputs.html&quot;&gt;HTML5 tests - inputs&lt;/a&gt; - This page tests the new input values of HTML5.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://www.quirksmode.org/html5/inputs_mobile.html&quot;&gt;HTML5 tests - inputs (mobile)&lt;/a&gt; - This page tests the new input values of HTML5 in mobile browsers.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://www.quirksmode.org/html5/tests/video.html&quot;&gt;HTML5 tests - video&lt;/a&gt; - This page tests the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;video&amp;gt;&lt;/code&gt; tag.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://www.quirksmode.org/html5/storage.html&quot;&gt;Local storage&lt;/a&gt; - Here is information about local storage and session storage.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://enable-cors.org&quot;&gt;Enable CORS&lt;/a&gt; - Enable cross-origin resource sharing&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>seajs 非权威指南</title>
   <link href="https://yuanyan.github.io/javascript/seajs-the-non-definitive-guide"/>
   <updated>2012-09-23T00:00:00+00:00</updated>
   <id>hhttps://yuanyan.github.io/javascript/seajs-the-non-definitive-guide</id>
   <content type="html">
&lt;p&gt;requirejs 已经用了近一年的时间，真心好用。
seajs 是从最近半年才开始实践，与 requirejs 相较是更值得去推广的模块化方案。&lt;/p&gt;

&lt;p&gt;一直致力于在前端模块化上布道中，也因此在两年前开始了 modulejs 的探索，至今未停止脚步。&lt;/p&gt;

&lt;h2 id=&quot;迈出第一步&quot;&gt;迈出第一步&lt;/h2&gt;

&lt;p&gt;掀起seajs的盖头来:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;script src=&quot;path/to/sea.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script&amp;gt;
seajs.use(&quot;main&quot;);
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;另一种方式：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;script data-main=&quot;main&quot; src=&quot;path/to/sea.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;seajs初始化时会自动去遍历查找seajs的script的data-main属性， data-main=”main” 完全等同于 seajs.use(“main”);&lt;/p&gt;

&lt;h2 id=&quot;配置&quot;&gt;配置&lt;/h2&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;seajs.config({
    base: &quot;&quot;
    ,alias: {}
    ,map: {}
    ,preload: []
    ,debug: true
    ,charset: &apos;utf-8&apos;
});
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;base 默认值为 path/to/sea.js 的中 path/to 路径&lt;/p&gt;

&lt;h2 id=&quot;别名配置&quot;&gt;别名配置&lt;/h2&gt;

&lt;p&gt;官方文档已非常详细：https://github.com/seajs/seajs/issues/258&lt;/p&gt;

&lt;h2 id=&quot;那些你需要知道的配置约定&quot;&gt;那些你需要知道的配置约定&lt;/h2&gt;

&lt;p&gt;别名配置 {jquery: ‘1.7.2’}  会自动被转换为  {jquery: ‘jquery/1.7.2/jquery’}，如果你的目录是 jquery/x.x.x/jquery 的结构, 配置上会
看上去清爽许多，对于不了解此约定的童鞋读配置时可能会一头雾水。&lt;/p&gt;

&lt;p&gt;这是seajs默认的处理方式，目前从配置上还不允许关闭此处理，如果的你的真实jquery文件是 以版本号 1.7.2.js 格式命名的，可能就悲剧了。&lt;/p&gt;

&lt;h2 id=&quot;配置map避免请求缓存&quot;&gt;配置map避免请求缓存&lt;/h2&gt;

&lt;p&gt;避免缓存的方案是在请求上加上时间戳，现在我们让所有的请求都加上时间戳：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;seajs.config({
    map: [
        [/^.*$/, function(url) {
            return url += (url.indexOf(&apos;?&apos;) === -1 ? &apos;?&apos; : &apos;&amp;amp;&apos;) + &apos;ts=&apos; + new Date；
        }]
    ]
})
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;seajs 提供一种快速配置的方式来避免缓存，原理与上面完全一致：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;seajs.config({
    debug : 2;
});
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;预加载&quot;&gt;预加载&lt;/h2&gt;

&lt;p&gt;为了让IE6/7/8 支持 ES5 的一些API，我们会引入es5-shim来修补，而在这些古老的浏览器使用ES5 API必然需要预先加载好才可以继续执行。
通过preload 配置中的空字符串会被忽略掉这一约定，我们不仅可以预加载，还可以按特征检测来智能加载的，让高级浏览量无需额外的请求es-shim：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;seajs.config({
    alias:{
        &apos;es5-shim&apos;: &apos;//cdnjs.cloudflare.com/ajax/libs/es5-shim/1.2.4/es5-shim.min&apos;
    }
    ,preload:[Array.isArray ? &apos;&apos; : &apos;es5-shim&apos;]
})

seajs.use(&apos;main&apos;);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;seajs 中并不是读取到有preload配置就立即加载的，只能是通过 seajs.use 这个入口来触发执行预加载, 如上示例 seajs 会在执行 main 模块前确保
预加载完 es-shim, 其他方式都无法保证 es5-shim 模块已经加载并执行好。&lt;/p&gt;

&lt;h2 id=&quot;被加载的库没有用-define-包装怎么办&quot;&gt;被加载的库没有用 define 包装怎么办?&lt;/h2&gt;

&lt;p&gt;很多童鞋说我依赖的库是放在公共CDN上的，我没有权限去修改或添加一个符合CMD规范的版本，
如我们引用的是 google cdn 上的jquery地址： //ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js&lt;/p&gt;

&lt;p&gt;这时该怎么办，最简单粗暴的方式是拷贝到本地然后包装上一层，但CDN的优势也就随之放弃了。&lt;/p&gt;

&lt;p&gt;seajs 虽然没有原生支持对非CMD规范文件的支持，但通过seajs.modify 与 preload 组合可以让非CMD的文件也可以被正确的 require 到：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;seajs.config({
    alias:{
        &apos;jquery&apos;: &apos;//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min&apos;
    }
    ,preload:[&quot;jquery&quot;]
})

seajs.modify(&apos;jquery&apos;, function (require, exports, module) {
     module.exports = jQuery;
});

seajs.use(&apos;main&apos;);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;目前在seajs中如需使用 非CMD文件 preload 配置是必不可少。&lt;/p&gt;

&lt;h2 id=&quot;开发ing&quot;&gt;开发ing&lt;/h2&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;// main.js
define(function(require){
    var $ = require(&apos;jquery&apos;);
    var _ = require(&apos;undersoce&apos;);
    var qplus = require(&apos;qplus&apos;);


});
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;开发很顺心发布很揪心&quot;&gt;开发很顺心，发布很揪心&lt;/h2&gt;

&lt;p&gt;一切都顺顺利利的开发完成，这是值得庆贺的，感谢党与人民，最后就只剩打包发布了，
我们知道前端发布的必要条件之一是压缩合并文件，seajs提供了SPM工具来打包CMD规范的文件。&lt;/p&gt;

&lt;p&gt;但对与 MPA 与 SPA 需要不同的打包策略：&lt;/p&gt;

&lt;p&gt;对于 SPA 单页面应用来说我们需要尽量减少请求，相比版本升级时即使公共部分没有改变也需重复下载未变改的部分，
打包为一个文件对第一次访问用户往往会更快些。&lt;/p&gt;

&lt;p&gt;而对于 MPA 多页面应用我们的原则是尽量的分离公共部分与独立部分，如应用的A页面与B页面都分别使用了jquery，
但在发布时却把jquery分别打包在了a.js 与 b.js中，虽然请求数减少了，但却重复加载了公共的部分。&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Data URI 最佳实践</title>
   <link href="https://yuanyan.github.io/html5/datauri-best-practice"/>
   <updated>2012-08-21T00:00:00+00:00</updated>
   <id>hhttps://yuanyan.github.io/html5/datauri-best-practice</id>
   <content type="html">
&lt;h2 id=&quot;写在文章之前&quot;&gt;写在文章之前&lt;/h2&gt;

&lt;p&gt;业内常会有 Data URI 的利与弊、用与不用的讨论， 如此对于 Data URI 的认识也可更全面，这无可非议。但着眼计算机软硬件与网络带宽的发展，前端HTML5技术的风靡全球，是否考虑重新去审视下自己的技术方案？
老的技术方案固然可用，老的浏览器短期内固然需要去兼容，但新技术已箭在弦上，新的浏览器用户数日渐庞大，这早已不是发与不发，何时发的问题。难道我们不应该让高级浏览器用户群享受更好的用户体验吗？
细想对于图片优化技术中的常采用的 Sprites （雪碧图、精灵图）技术，&lt;a href=&quot;http://blog.vlad1.com/2009/06/22/to-sprite-or-not-to-sprite/&quot;&gt;又何尝不是有内存的问题&lt;/a&gt;？在不存在完美方案的现实下，新技术带来的性能提升，操作便利性难道不是更吸引你吗？&lt;/p&gt;

&lt;h2 id=&quot;data-uri-科普&quot;&gt;Data URI 科普&lt;/h2&gt;

&lt;p&gt;笔者对本文的定位是实践操作型，所以一些理论基础只点到为止。首先 Data URI 是什么？ 引用 &lt;a href=&quot;http://en.wikipedia.org/wiki/Data_URI_scheme&quot;&gt;Wikipedia&lt;/a&gt; 上对其的解释：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Data URI 是一种提供让外置资源的直接内嵌在页面中的方案。这种技术允许我们只需单次 HTTP 请求即可获取所有需要引用的图片与样式资源，
并因无需多次请求资源而变的高效。
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;在 RFC2397（http://tools.ietf.org/html/rfc2397）中定义了它格式规范：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;data:[&amp;lt;mime type&amp;gt;][;charset=&amp;lt;charset&amp;gt;][;base64],&amp;lt;encoded data&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;data-uri-初探&quot;&gt;Data URI 初探&lt;/h2&gt;

&lt;p&gt;看格式规范貌似不是很友好，我们以内嵌图片为例：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;img src=&quot;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA
AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO
9TXL0Y4OHwAAAABJRU5ErkJggg==&quot; alt=&quot;Red dot&quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;data:image/png;base64,&lt;/strong&gt; 是固定的格式, image/png 是图片的MIME类型，base64是数据编码方式。这里还有必要指出下
&lt;a href=&quot;http://zh.wikipedia.org/wiki/Base64&quot;&gt;Base64&lt;/a&gt; 编码后的数据会比原始数据大 4/3 左右，这与Base64 编码算法有关。
如需使用在电子邮件中，根据 RFC 822 规定，每 76 个字符，还需要加上一个回车换行，此时编码后数据长度大约为原长的135.1%。&lt;/p&gt;

&lt;p&gt;为验证理论的我们做如下的测试，分别对不同尺寸的图片进行Base64编码，与我们的预期一致，比原始数据增长了 1/3 ：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;图片尺寸 | 原始大小 | Base64大小 | 增长率 |
:-----------|:------------|:-------------|:-------------|
16*16 | 618 | 824 | 34.2%
24*24 | 1,063 | 1,420 | 33.6%
32*32 | 1,615 | 2,156 | 33.5%
42*42 | 2,510 | 3,348 | 33.4%
48*48 | 2,892 | 3,856 | 33.3%
96*96 | 8,217 | 10,956 | 33.3%
350*350 | 49,899 | 66,532 | 33.3%
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;图片是使用 Data URI 最常用的情景，但 Data URI 是与资源类型无关的规范，您也可以使用 Data URI 内嵌其他资源:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;var cvs = &apos;data:text/csv;charset=utf-8,&apos; + encodeURIComponent(csv);
var html = &apos;data:text/html;charset=utf-8,&apos; + encodeURIComponent(html);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;data-uri-兼容性&quot;&gt;Data URI 兼容性&lt;/h2&gt;

&lt;p&gt;在前端，浏览器兼容性几乎每个技术都逃不过的话题，检阅 Data URI 的兼容性：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Firefox 2+&lt;/li&gt;
  &lt;li&gt;Opera 7.2+&lt;/li&gt;
  &lt;li&gt;Chrome++&lt;/li&gt;
  &lt;li&gt;Safari++&lt;/li&gt;
  &lt;li&gt;Internet Explorer 8+&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;大部分主流浏览器都早已支持 Data URI，IE8 虽支持但其最大长度不能超过32K的数据，在 IE9 下已解除此限制，IE 详细的文档可细读&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/cc848897(VS.85).aspx&quot;&gt;微软官方文档&lt;/a&gt;。
剩下的依旧是面对在国内还是 A 类浏览量的 IE 6/7， 我们可以采用与 Data URI 类似的 &lt;a href=&quot;http://en.wikipedia.org/wiki/MHTML&quot;&gt;MHTML&lt;/a&gt; （笔者认为其设计上比 Data URI 是更优秀的，考虑到了内嵌数据的重用）.
MHTML 详细的介绍不在本文的讨论范围，但需要指出的是微软在 2011 年发布了 &lt;a href=&quot;http://technet.microsoft.com/zh-CN/security/advisory/2501696&quot;&gt;MHTML 中的漏洞可能允许信息泄露&lt;/a&gt; 的补丁，
将造成 MHTML 无法被引用的问题，所以在 IE 中使用 MHTML 的方案会有极大的风险，权且当扩展知识面不推荐采用。&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;http://technet.microsoft.com/zh-CN/security/advisory/2501696&lt;/li&gt;
  &lt;li&gt;http://www.microsoft.com/china/security/bulletins/ms03-014.mspx&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;data-uri-最佳实践&quot;&gt;Data URI 最佳实践&lt;/h2&gt;

&lt;p&gt;在 Data URI 转换之前我们不进行图片合并，而是直接使用小图片，如此省去了合图定位的麻烦，&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;background-image:url(&quot;data:image/png;base64,iVBORw0KGgoAAA...ElFTkSuQmCC&quot;);
*background-image:url(http://cdn.example.com/foo.gif);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;比较数据：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;图片尺寸 | 原始大小 | Base64大小 | Gzip大小 |  Gzip压缩率 | 增长率 |
:-----------|:------------|:-------------|:-------------|:-------------|:-------------|
16*16 | 618 | 824 | 668 | 81.1% | 108.8%
24*24 | 1,063 | 1,420 | 1,119 | 78.8% | 5.3%
32*32 | 1,615 | 2,156 | 1,670 | 77.5% | 3.9%
42*42 | 2,510 | 3,348 | 2,568 | 76.7% | 2.3%
48*48 | 2,892 | 3,856 |  2940 | 76.2% | 1.7%
96*96 | 8,217 | 10,956 | 8304 | 75.8% | 1.1%
350*350 | 49,899 | 66,532 | 50,095 | 75.3% | 0.4%
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;diy-生成工具&quot;&gt;DIY 生成工具&lt;/h2&gt;

&lt;p&gt;Node 是名副其实的前端开发得力助手，只用3行代码就能让一张图片转换成Base64编码：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;var body = fs.readFileSync(&apos;./foo.png&apos;, &apos;binary&apos;);  // 输入
var image = new Buffer(body, &apos;binary&apos;).toString(&apos;base64&apos;); // base64编码
var base64 = &apos;data:image/png;base64,&apos; + image;  // 输出
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Datauri 格式数据需要更多CPU计算来呈现图片，也许在性能稍弱的PC上，额外请求图片的方案可能更早的渲染出图片，尤其在移动端有限CPU的情景下，一定要慎用。&lt;/p&gt;

&lt;p&gt;这里折中方案是限定转换的条件，只有小于 2K 的小图才被转换成Base64编码， 2K 是比较推荐的阀值。&lt;/p&gt;

&lt;h2 id=&quot;参考&quot;&gt;参考&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.nczonline.net/blog/2009/10/27/data-uris-explained/&quot;&gt;Data URIs explained&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.99css.com/archives/492&quot;&gt;Data URI&amp;amp;MHTML: 用还是不用？&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>Appcache Facts 中译版</title>
   <link href="https://yuanyan.github.io/html5/appcache-facts"/>
   <updated>2012-08-16T00:00:00+00:00</updated>
   <id>hhttps://yuanyan.github.io/html5/appcache-facts</id>
   <content type="html">
&lt;p&gt;Application cache 是 HTML5 中在规范完整性上比较糟糕的特性之一，规范上的不到位导致浏览器厂商在实现上也存在些许差异，而产生本文档的目的即让开发者们知晓那些潜规则，摆脱问题的困惑与束缚，正确的使用应用缓存真正让 Web 加速。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fact&lt;/strong&gt; ：设计 Appcache 的目的虽是能让 Web 应用能在离线的情况的运行而无需要求连接网络，但同时 Appcache 也可在网络在线的情况的使用，如此来减少页面需要加载的资源数量来提速页面，速度上将是一个数量级的提升。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fact&lt;/strong&gt; ：服务器返回 manifest 文件的MIME类型必须是 text/cache-manifest, 否则虽配置 manifest 文件但 Appcache 功能并不会启用。&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;建议 manifest 文件以 .appcache 为文件后缀名，
并在 Web 服务器中添加 MIME 类型类型，如在 Apache 的.htaccess 配置中添加：
AddType text/cache-manifest .appcache
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Fact&lt;/strong&gt; ：Appcache 的 manifest 文件有三个可选的配置项目： CACHE， NETWORK， FALLBACK。&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;CACHE 项配置所有需要存储在本地应用缓存中的资源文件，浏览器会在页面加载完
成后即时的自动在后台下载。如果浏览器之前已经下载过CACHE列表中的某个资源则
不会再次下载。

NETWORK 项配置与 CACHE 正相反，它告诉浏览器哪些资源要求是在有网络的环境下，
如后台的API接口调用，可以配置在 NETWORK 项。 如我们的接口地址是 http://example.com/api/
前缀格式的URL，则只需配置其URL的前缀格式，无需列出所有URL，浏览器会自动去匹配。

如果我们需要配置为所有的URL地址为CACHE或NETWORK，Chrome 与 Safari 要求用户
配置为 *，Firefox要求为 http://* 和 https://*，兼容上考虑我们可在配置
中分别加入 *，http://* 和 https://* 使其在所有浏览器中都被识别。

FALLBACK 项配置为告诉浏览器在离线环境下或服务器故障时这些网络资源不可用
时的使用哪些替代资源。
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Fact&lt;/strong&gt; ：在SSL安全连接下，所有在 manifest 配置的资源列表需符合同源策略。即所有的地址都必须是相对地址。但Chrome除外，在SSL下，即使有非同源的资源，Chrome仍旧会下载至应用缓存中。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fact&lt;/strong&gt; ：manifest 文件任何的改变包括注释都会触发浏览器更新应用缓存中的所有资源。通常 manifest 的配置策略在每次发布是并不会有改变，为了更新应用缓存我们会在 manifest 的中加入版本注释，在下次发布中则修改 # version 1 注释来知会浏览器更新应用缓存。&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;CACHE MANIFEST
# version 1
CACHE
/logo.png
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Fact&lt;/strong&gt; ：当需要更新已存在的应用缓存时，浏览器会向服务器发送标准的  If-Modified-Since 请求头，当远程的资源未改变与本地缓存一致时，浏览器则不再重新下载。浏览器不会自动去检测列表中资源，必须手动去改变 manifest 文件来触发，我们推荐通过改变 manifest 中的版本注释来触发检测，简单且有效。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fact&lt;/strong&gt; ：manifest 中的任何资源的改变只在的下次页面加载中生效。因为如页面已经被缓存，浏览器会立即从缓存中获取资源，然后才开启后台进程去检测 manifest 文件中是否有资源需要被刷新。所以最新版本的资源只会在浏览器下次启动时被从缓存中获取。我们可以绑定 updateready 事件来获知后台更新完新版本资源的时机，然后提示用户是否需重新加载页面：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;if (window.applicationCache) {
    applicationCache.addEventListener(&apos;updateready&apos;, function() {
        if (confirm(&apos;页面更新完成，是否重新加载?&apos;)) {
            window.location.reload();
        }
    });
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;老版本如能提供正常的功能体验的情况下，建议在当次打开时继续使用老版本，或在页面顶部提醒用户避免突然的弹窗确认。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fact&lt;/strong&gt; ：如在 CACHE 项配置的任何一个资源浏览器在检索时服务器返回 404 或 500 时，此时整个 CACHE 配置将被忽略。浏览器会保证 CACHE 项的完整性，并在下次页面加载时重新拉取 manifest 文件继续按此原则检索资源，直到 CACHE 项中配置的资源全部可用时。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fact&lt;/strong&gt; ：在每次页面加载后，浏览器都会去检索当前页面的 manifest 文件是否可用，如服务器返回 404 或 500，所有已经被缓存在本地的离线资源都会被忽略。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fact&lt;/strong&gt; ：即使我们没有在 manifest 文件中加入当前包含 manifest 的页面地址，浏览器会默认把其添加到应用缓存。这意味着我们无需在 manifest 中列出每个网页地址，因为只要是用户访问的每个页面都包含 manifest 文件浏览器会隐式的将其添加进应用缓存中。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fact&lt;/strong&gt; ：Chrome 可以在地址中输入 chrome://appcache-internals/ 列出已经被浏览器缓存的网站，并可以查看所有网站的应用缓存占用空间，最后修改时间，还可直接对其进行删除。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fact&lt;/strong&gt; ：Firefox 对于请求返回头配置为 Cache-control: no-store 的资源一律不缓存，即使是显式配置在 manifest 文件中。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fact&lt;/strong&gt; ：当应用需要使用 appcache 时，Firefox 会在首次打开应用时询问用户是否授权使用。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fact&lt;/strong&gt; ：Android Webview 默认没有开启 Appcache，可通过如下配置在Webview中支持Appcache功能&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;webView.getSettings().setDomStorageEnabled(true);
// 设置缓存总容量为 8 mb
webView.getSettings().setAppCacheMaxSize(1024*1024*8);
// 缓存路径
String appCachePath = getApplicationContext().getCacheDir().getAbsolutePath();
webView.getSettings().setAppCachePath(appCachePath);
webView.getSettings().setAllowFileAccess(true);
webView.getSettings().setAppCacheEnabled(true);
// 设置缓存策略
webView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;参考资源&quot;&gt;参考资源&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;AppCacheFacts Demo Site  – &lt;a href=&quot;http://appcachefacts.info/demo/&quot;&gt;Demo&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Open Web Camp IV presentation &lt;a href=&quot;http://appcachefacts.info/peterlubbers-owc4/index.html&quot;&gt;Building Offline Web Applications with AppCache (2012)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Dive Into HTML5 – &lt;a href=&quot;http://diveintohtml5.info/offline.html&quot;&gt;Let’s Take This Offline&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Google Code Blog – &lt;a href=&quot;http://googlecode.blogspot.com/2009/04/gmail-for-mobile-html5-series-using.html&quot;&gt;Using AppCache to Launch Offline&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;HTML5 Rocks – &lt;a href=&quot;http://www.html5rocks.com/tutorials/appcache/beginner/&quot;&gt;A Beginner’s Guide to Using the Application Cache&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;MDN Doc Center – &lt;a href=&quot;https://developer.mozilla.org/en/offline_resources_in_firefox&quot;&gt;Offline resources in Firefox&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Safari Developer Library – &lt;a href=&quot;http://developer.apple.com/library/safari/#documentation/appleapplications/reference/SafariWebContent/Client-SideStorage/Client-SideStorage.html&quot;&gt;Storing Data on the Client&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Online validator, JSON(P) validation API, and TextMate bundle) – &lt;a href=&quot;http://manifest-validator.com&quot;&gt;Cache Manifest Validator&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;A List Apart  – &lt;a href=&quot;http://www.alistapart.com/articles/application-cache-is-a-douchebag/&quot;&gt;Application Cache is a Douchebag&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;© 2012 &lt;a href=&quot;http://twitter.com/shinypb&quot;&gt;Mark Christian&lt;/a&gt; &amp;amp; &lt;a href=&quot;http://twitter.com/ded&quot;&gt;Dustin Diaz&lt;/a&gt;. License: &lt;a href=&quot;http://creativecommons.org/licenses/by/3.0/&quot;&gt;CC Attribution 3.0&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Javascript 安全方案</title>
   <link href="https://yuanyan.github.io/solution/javascript-security"/>
   <updated>2012-08-14T00:00:00+00:00</updated>
   <id>hhttps://yuanyan.github.io/solution/javascript-security</id>
   <content type="html">
&lt;p&gt;这是一篇关于JavaScript安全的文章，但也不限于JavaScript。
前端安全的范围大致都在XSS（跨站脚本攻击）与 CSRF（跨站请求伪造）这两个领域，下面的分享与讨论也都可认为是这几个主题的延伸与扩展。&lt;/p&gt;

&lt;p&gt;对于前端安全，可能很多人有这样一个疑问：后台往往已经做了安全处理，为啥前端还需要再处理一次呢？所有前端接收到数据都应该被认为是
不可信的，因为我们无法保证后台数据一定是安全的，即使是自己的后台也有可能存在数据存储的入口是多个的，任何一个入口在存储数据式发生安全问题，
都会可能导致展现数据前端发生被攻击的风险。&lt;/p&gt;

&lt;p&gt;进入正题，先从考虑下面的代码开始，是否有发现问题？&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;script&amp;gt;
  var str = &quot;&amp;lt;/script&amp;gt;&amp;lt;script&amp;gt;alert(&apos;i am flaw&apos;);&amp;lt;/script&amp;gt;&quot;;
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;这断代码最后的执行结果是 alert i am flaw 的填出框，这与HTML解析机制有关，HTML从上而下进行分析，解析引擎遇到
第一个起始标签 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;script&amp;gt;&lt;/code&gt; 时把其压入栈中，直到遇到紧随的第一个闭合标签 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;/script&amp;gt;&lt;/code&gt;，导致引擎会认为&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;script&amp;gt; var str = &quot; &amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;是第一段JavaScript代码并执行。然后继续按以上规则解析后续文本，因此引擎会认为下面是第二段代码并执行：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;script&amp;gt;alert(&apos;i am flaw&apos;);&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;而 “; &amp;lt;/script&amp;gt; 则被分为两部对待， “; 被视为文本内容并显示，而 &amp;lt;/script&amp;gt; 则会被认为是未闭合的非法标签。此时浏览器会报语法错误，提示你标签非法，
如Chrome下提示 Uncaught SyntaxError: Unexpected token ILLEGAL。&lt;/p&gt;

&lt;p&gt;简单的开胃菜后讲些干货~&lt;/p&gt;

&lt;h3 id=&quot;关于css样式&quot;&gt;关于CSS样式&lt;/h3&gt;

&lt;p&gt;在很多有个人主页的站点是支持用户自定义样式的，那如何过滤用户定义的非法CSS属性，则是需要考虑的安全问题之一。&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;if(css.match(/behavior:|content:|javascript:|binding|expression|\@import/)){
    throw new Error(&quot;Illegal CSS&quot;);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;过滤 expression&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;color:expression(alert(\&quot;hello\&quot;)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;过滤 @import&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;@import &apos;unsafe.css&apos;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;过滤 behavior&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;behavior: url(unsafe.htc)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;过滤 binding&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;-moz-binding: url(&quot;http://www.mozilla.org/xbl/htmlBindings.xml#checkbox&quot;);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;过滤 url&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;url(javascript:alert(3))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;过滤 content&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;content: &quot; (&quot; attr(href) &quot;)&quot;;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;未完待续…&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Third-party Javascript 编程</title>
   <link href="https://yuanyan.github.io/javascript/third-party-javascript-programming"/>
   <updated>2012-08-08T00:00:00+00:00</updated>
   <id>hhttps://yuanyan.github.io/javascript/third-party-javascript-programming</id>
   <content type="html">
&lt;h2 id=&quot;关于-third-party-javascript&quot;&gt;关于 Third-party JavaScript&lt;/h2&gt;
&lt;p&gt;什么是Third-party JavaScript？翻译成中文为第三方JavaScript，举个例子：用户甲访问乙方的网站，但乙方页面却包含来自丙方的JavaScript代码并执行，我们称来自丙方的JavaScript为第三方JavaScript。第三方JavaScript其实我们早已非常熟悉，只是未曾去了解他们的统一称呼。如我们经常在博客中看到博主使用了 &lt;a href=&quot;http://disqus.com&quot;&gt;Disqus&lt;/a&gt; 提供评论服务，需在页面引入如下JavaScript代码片断：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;script type=&quot;text/javascript&quot;&amp;gt;
    var disqus_shortname = &apos;madscript&apos;; // required: replace example with your forum shortname

    /* * * DON&apos;T EDIT BELOW THIS LINE * * */
    (function() {
        var dsq = document.createElement(&apos;script&apos;); dsq.type = &apos;text/javascript&apos;; dsq.async = true;
        dsq.src = &apos;http://&apos; + disqus_shortname + &apos;.disqus.com/embed.js&apos;;
        (document.getElementsByTagName(&apos;head&apos;)[0] || document.getElementsByTagName(&apos;body&apos;)[0]).appendChild(dsq);
    })();
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;再如 &lt;a href=&quot;http://www.jiathis.com/&quot;&gt;Jisthis&lt;/a&gt; 提供的“分享到”侧栏需引入：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;!-- JiaThis Button BEGIN --&amp;gt;
&amp;lt;script type=&quot;text/javascript&quot; src=&quot;http://v3.jiathis.com/code/jiathis_r.js?uid=1336206755505427&amp;amp;move=0&quot; charset=&quot;utf-8&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;!-- JiaThis Button END --&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;以上举例的两个是具有UI界面并直接服务甲可以被甲感知的第三方JavaScript，既然有些具有UI的，当然还有一些是无UI的或常规情况下无UI的第三方JavaScript，这其中流量最大的应是 Google 提供的面向乙方提供的网站访问分析服务&lt;a href=&quot;http://www.google.com/analytics/&quot;&gt;Google Analytics&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;script type=&quot;text/javascript&quot;&amp;gt;
  var _gaq = _gaq || [];
  _gaq.push([&apos;_setAccount&apos;, &apos;UA-19059856-3&apos;]);
  _gaq.push([&apos;_trackPageview&apos;]);

  (function() {
    var ga = document.createElement(&apos;script&apos;); ga.type = &apos;text/javascript&apos;; ga.async = true;
    ga.src = (&apos;https:&apos; == document.location.protocol ? &apos;https://ssl&apos; : &apos;http://www&apos;) + &apos;.google-analytics.com/ga.js&apos;;
    var s = document.getElementsByTagName(&apos;script&apos;)[0]; s.parentNode.insertBefore(ga, s);
  })();
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;参考&quot;&gt;参考&lt;/h2&gt;

&lt;p&gt;来自 &lt;a href=&quot;https://twitter.com/bentlegen&quot;&gt;Ben Vinegar&lt;/a&gt; 的分享：&lt;/p&gt;

&lt;iframe src=&quot;http://www.slideshare.net/slideshow/embed_code/8281214&quot; width=&quot;597&quot; height=&quot;486&quot; frameborder=&quot;0&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot; scrolling=&quot;no&quot; style=&quot;border:1px solid #CCC;border-width:1px 1px 0;margin-bottom:5px&quot; allowfullscreen=&quot;allowfullscreen&quot;&gt; &lt;/iframe&gt;

&lt;p&gt;未完待续…&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>高性能Web前端</title>
   <link href="https://yuanyan.github.io/performance/high-performance-frontend"/>
   <updated>2012-07-07T00:00:00+00:00</updated>
   <id>hhttps://yuanyan.github.io/performance/high-performance-frontend</id>
   <content type="html">
&lt;h2 id=&quot;高性能-html&quot;&gt;高性能 HTML&lt;/h2&gt;

&lt;h4&gt;避免使用Iframe&lt;/h4&gt;
&lt;p&gt;Iframe也叫内联frame，可以把一个HTML文档嵌入到另一个文档中。使用iframe的好处是被嵌入的文档可以完全独立于其父文档，凭借此特点我们通常可以使浏览器模拟多线程，需要注意的是使用iframe并不会增加同域名下的并行下载数，浏览器对同域名的连接总是共享浏览器级别的连接池，即使是跨窗口或跨标签页，这在所有主流浏览器都是如此。也因为这样这让iframe带来的好处大打折扣。&lt;/p&gt;
&lt;p&gt;&lt;span id=&quot;more-1627&quot;&gt;&lt;/span&gt;在页面加载过程中iframe元素会阻塞父文档onload事件的触发，而开发者程序通常会在onload事件触发时初始化UI操作。例如，设置登录区域的焦点。因为用户习惯等待这一操作，所以尽可能的让onload事件触发从而使用户的等待时间变短是非常重要的。另外开发者会把一些重要的行为绑定在unload事件上，而不幸的是在一些浏览器中，只有当onload事件触发后unload事件才能触发，如果onload事件长时间未触发，而用户已经离开当前页面，那么unload事件也将永远得不到触发。&lt;br /&gt;
那是否有方案可以让onload事件不被iframe阻塞吗？有个简单的解决方案来避免onload事件被阻塞，使用JavaScript动态的加载iframe元素或动态设置iframe的src属性：&lt;/p&gt;
&lt;pre&gt; &amp;lt;iframe id=iframe1 &amp;gt;&amp;lt;/iframe&amp;gt;
 document.getElementById(‘iframe1’).setAttribute(‘src’， ‘url’);&lt;/pre&gt;
&lt;p&gt;但其仅在高级浏览器 中有效，对于Internet Explorer 8及以下的浏览器无效。除此之外我们必须知道iframe是文档内最消耗资源的元素之一，在&lt;a onclick=&quot;javascript:pageTracker._trackPageview(&apos;/outgoing/stevesouders.com/efws/costofelements.php&apos;);&quot; href=&quot;http://stevesouders.com/efws/costofelements.php&quot;&gt;Steve Souders 的测试中 &lt;/a&gt;，在测试页面中分别加载100个A、DIV、SCRIPT、STYLE和 IFRAME元素，并且分别在Chrome、Firefox、Internet Explorer、Opera、Safari中运行了10次。结果显示创建iframe元素的开销比创建其他类型的DOM元素要高1~2个数量级。在测试中所有的DOM元素都是空的，如加载大的脚本或样式块可能比加载某些iframe元素耗时更长，但从基准测试结果来看，即使是空的iframe，其开销也是非常昂贵的，鉴于iframe的高开销，我们应尽量避免使用。尤其是对于移动设备，对于目前大部分还是只有有限的CPU与内存的情况下，更应避免使用iframe。&lt;/p&gt;
&lt;h4&gt;避免空链接属性&lt;/h4&gt;
&lt;p&gt;空的链接属性是指img、link、script、ifrrame元素的src或href属性被设置了，但是属性却为空。如&amp;lt;img src=””&amp;gt;，我们创建了一个图片，并且暂时设置图片的地址为空，希望在未来动态的去修改它。但是即使图片的地址为空，浏览器依旧会以默认的规则去请求空地址：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Internet Explorer 8及以下版本浏览器只在img类型元素上出现问题，IE会把img的空地址解析为当前页面地址的目录地址。例如：如果当前页面地址为&lt;a onclick=&quot;javascript:pageTracker._trackPageview(&apos;/outgoing/example.com/dir/page.html&apos;);&quot; href=&quot;http://example.com/dir/page.html&quot;&gt;http://example.com/dir/page.html&lt;/a&gt;，IE会把空地址解析为&lt;a onclick=&quot;javascript:pageTracker._trackPageview(&apos;/outgoing/example.com/dir/&apos;);&quot; href=&quot;http://example.com/dir/&quot;&gt;http://example.com/dir/&lt;/a&gt;地址并请求。&lt;/li&gt;
&lt;li&gt;早些版本的Webkit内核浏览器 与Firefox 会把空地址解析为当前页面的地址。如果页面内有多个空链接属性元素，当前页面的服务器则会被请求多次，增加服务器的负载。相较桌面浏览器对内核的更新升级较积极，这个问题在ios与android系统的移动浏览器上问题可能较严重。&lt;/li&gt;
&lt;li&gt;幸运的是所有主流浏览器面对iframe的src属性为空时，会把空地址解析为about:blank地址，而不会向服务器发出额外的请求。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;避免节点深层级嵌套&lt;/h4&gt;
&lt;p&gt;深层级嵌套的节点在初始化构建时往往需要更多的内存占用，并且在遍历节点时也会更慢些，这与浏览器构建DOM文档的机制有关。例如下面HTML代码：&lt;/p&gt;
&lt;pre&gt; &amp;lt;html&amp;gt;
 &amp;lt;body&amp;gt;
 &amp;lt;p&amp;gt;
 Hello World
 &amp;lt;/p&amp;gt;
 &amp;lt;div&amp;gt; &amp;lt;img src=&quot;example.png&quot;/&amp;gt;&amp;lt;/div&amp;gt;
 &amp;lt;/body&amp;gt;
 &amp;lt;/html&amp;gt;&lt;/pre&gt;
&lt;p&gt;通过浏览器HTML解析器的解析，浏览器会把整个HTML文档的结构存储为DOM树结构。当文档节点的嵌套层次越深，构建的DOM树层次也会越深。&lt;/p&gt;
&lt;h4&gt;缩减HTML文档大小&lt;/h4&gt;
&lt;p&gt;提高下载速度最显而易见的方式就是减少文件的大小，特别是压缩内嵌在HTML文档中的JavaScript和CSS代码，这能使得页面体积大幅精简。除此之外减少HTML文档大小还可以采取下面几种方法：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;删掉HTM文档对执行结果无影响的空格空行和注释&lt;/li&gt;
&lt;li&gt;避免Table布局&lt;/li&gt;
&lt;li&gt;使用HTML5&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;显式指定文档字符集&lt;/h4&gt;
&lt;p&gt;HTML页面开始时指定字符集，有助于浏览器可以立即开始解析HTML代码。HTML文档通常被解析为一序列的带字符集编码信息的字符串通过internet传送。字符集编码在HTTP响应头中，或者HTML标记中指定。浏览器根据获得的字符集，把编码解析为可以显示在屏幕上的字符。如果浏览器不能获知页面的编码字符集，一般都会在执行脚本和渲染页面前，把字节流缓存，然后再搜索可进行解析的字符集，或以默认的字符集来解析页面代码，这会导致消耗不必要的时间。为了避免浏览器把时间花费在搜寻合适的字符集来进行解码，所以最好在文档中总是显式的指定页面字符集。&lt;/p&gt;
&lt;h4&gt;显式设置图片的宽高&lt;/h4&gt;
&lt;p&gt;当浏览器加载页面的HTML代码时，有时候需要在图片下载完成前就对页面布局进行定位。如果HTML里的图片没有指定尺寸（宽和高），或者代码描述的尺寸与实际图片的尺寸不符时，浏览器则要在图片下载完成后再“回溯”该图片并重新显示，这会消耗额外时间。所以，最好为页面里的每一张图片都指定尺寸，不管是在页面HTML里的&amp;lt;img&amp;gt;标签，还是在CSS里。&lt;/p&gt;
&lt;pre&gt;&amp;lt;img src=&quot;hello.png&quot; width=&quot;400&quot; height=&quot;300&quot;&amp;gt;&lt;/pre&gt;
&lt;h4&gt;避免脚本阻塞加载&lt;/h4&gt;
&lt;p&gt;当浏览器在解析常规的script标签时，它需要等待script下载完毕，再解析执行，而后续的HTML代码只能等待。为了避免阻塞加载，应把脚步放到文档的末尾，如把script标签插入在body结束标签之前：&lt;/p&gt;
&lt;pre&gt; &amp;lt;script src=&quot;example.js&quot; &amp;gt;&amp;lt;/script&amp;gt;
 &amp;lt;/body&amp;gt;&lt;/pre&gt;

&lt;h2 id=&quot;高性能-css&quot;&gt;高性能 CSS&lt;/h2&gt;

&lt;h4 align=&quot;left&quot;&gt;避免使用@import&lt;/h4&gt;
&lt;p align=&quot;left&quot;&gt;有两种方式加载样式文件，一种是link元素，另一种是CSS 2.1加入@import。而在外部的CSS文件中使用@import会使得页面在加载时增加额外的延迟。虽然规则允许在样式中调用@import来导入其它的CSS，但浏览器不能并行下载样式，就会导致页面增添了额外的往返耗时。比如，第一个CSS文件first.css包含了以下内容：@import url(“second.css”)。那么浏览器就必须先把first.css下载、解析和执行后，才发现及处理第二个文件second.css。简单的解决方法是使用&amp;lt;link&amp;gt;标记来替代@import，比如下面的写法就能够并行下载CSS文件，从而加快页面加载速度：&lt;span id=&quot;more-1629&quot;&gt;&lt;/span&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;link rel=&quot;stylesheet&quot; href=&quot;&quot;first.css&quot;&quot; /&amp;gt;
&amp;lt;link rel=&quot;stylesheet&quot; href=&quot;second.css&quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p align=&quot;left&quot;&gt;需要注意的是一个页面中的CSS文件不宜过多，否则应该简化及合并外部的CSS文件以节省往返请求时间(RTT)提升页面加载速度。&lt;/p&gt;
&lt;h4 align=&quot;left&quot;&gt;避免AlphaImageLoader滤镜&lt;/h4&gt;
&lt;p align=&quot;left&quot;&gt;IE独有属性AlphaImageLoader用于修正7.0以下版本中显示PNG图片的半透明效果。这个滤镜的问题在于浏览器加载图片时它会终止内容的呈现并且冻结浏览器。在每一个元素（不仅仅是图片）它都会运算一次，增加了内存开支，因此它的问题是多方面的。完全避免使用AlphaImageLoader的最好方法就是使用PNG8格式来代替，这种格式能在IE中很好地工作。如果你确实需要使用AlphaImageLoader，请使用下划线_filter又使之对IE7以上版本的用户无效。&lt;/p&gt;
&lt;h4 align=&quot;left&quot;&gt;避免CSS表达式&lt;/h4&gt;
&lt;p align=&quot;left&quot;&gt;CSS表达式是动态设置CSS属性的强大（但危险）方法。Internet Explorer从第5个版本开始支持CSS表达式。下面的例子中，使用CSS表达式可以实现隔一个小时切换一次背景颜色：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;background-color: expression((new Date()).getHours()%2?&quot;#FFFFFF&quot;: &quot;#000000&quot; );
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p align=&quot;left&quot;&gt;如上所示，expression中使用了JavaScript表达式。CSS属性根据JavaScript表达式的计算结果来设置。expression方法在其它浏览器中不起作用，因此在跨浏览器的设计中单独针对Internet Explorer设置时会比较有用。&lt;/p&gt;
&lt;p align=&quot;left&quot;&gt;表达式的问题就在于它的计算频率要比我们想象的多。不仅仅是在页面显示和缩放时，就是在页面滚动、乃至移动鼠标时都会要重新计算一次。给CSS表达式增加一个计数器可以跟踪表达式的计算频率。在页面中随便移动鼠标都可以轻松达到10000次以上的计算量。一个减少CSS表达式计算次数的方法就是使用一次性的表达式，它在第一次运行时将结果赋给指定的样式属性，并用这个属性来代替CSS表达式。如果样式属性必须在页面周期内动态地改变，使用事件句柄来代替CSS表达式是一个可行办法。如果必须使用CSS表达式，一定要记住它们要计算成千上万次并且可能会对你页面的性能产生影响。&lt;/p&gt;
&lt;h4 align=&quot;left&quot;&gt;避免通配选择器&lt;/h4&gt;
&lt;p align=&quot;left&quot;&gt;CSS选择器对性能的影响源于浏览器匹配选择器和文档元素时所消耗的时间，所以优化选择器的原则是应尽量避免需要消耗更多匹配时间的选择器。而在这之前我们需要了解CSS选择器匹配的机制，如例子的子选择器规则：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#header &amp;gt; a {font-weight:blod;}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p align=&quot;left&quot;&gt;我们中的大多数人都是从左到右的阅读习惯，可能也会习惯性的设定浏览器也是从左到右的方式进行匹配规则，因为会推测这条规则的开销并不高。我们这样假象浏览器会像这样的方式工作：找到唯一的id为header为的元素，然后把这个样式规则应用到直系子元素中的a元素上。我们知道文档中只有一个id为header的元素，并且它只有几个a类型的子节点，所以这个CSS选择器应该相当高效。&lt;/p&gt;
&lt;p align=&quot;left&quot;&gt;事实上，却恰好相反，CSS选择器是从右到左进行规则匹配。了解这个机制后，例子中看似高效的选择器在实际中的匹配开销是很高的，浏览器必须遍历页面中所有的a元素并且确定其父元素的id是否为header。&lt;/p&gt;
&lt;p align=&quot;left&quot;&gt;如果把例子的子选择器改为后代选择器则会开销更多，在遍历页面中所有a元素后还需向其上级遍历直到根节点。&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#header a {font-weight:blod;}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p align=&quot;left&quot;&gt;理解了CSS选择器从右到左匹配的机制后，可以理解选择器中最右边的规则往往决定了浏览器继续左移匹配的工作量，我们把最右边选择规则称之为关键选择器。&lt;/p&gt;
&lt;p align=&quot;left&quot;&gt;通配选择器使用 * 符合表示，可匹配文档中的每一个元素。如下例规则将所有元素的字体大小设置为20px：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;* { font-size:20px;}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p align=&quot;left&quot;&gt;通配选择器作用于所有的元素，如规则最右边为通配符：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;.selected * {color: red;}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p align=&quot;left&quot;&gt;浏览器匹配文档中所有的元素后分别向上逐级匹配class为selected的元素，直到文档的根节点，因此其匹配开销是非常大的，通常比开销最小的ID选择器高出1~3个数量级，所以应避免使用关键选择器是通配选择器的规则。&lt;/p&gt;
&lt;h4 align=&quot;left&quot;&gt;避免单规则的属性选择器&lt;/h4&gt;
&lt;p align=&quot;left&quot;&gt;属性选择器根据元素的属性是否存在或其属性值进行匹配，如下例规则会把herf属性值等于”#index”的链接元素设置为红色：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;.selected [href=”#index”] {color: red;}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p align=&quot;left&quot;&gt;但其匹配开销是非常大的，浏览器先匹配所有的元素，检查其是否有href属性并且herf属性值等于”#index”， 然后分别向上逐级匹配class为selected的元素，直到文档的根节点。所以应避免使用关键选择器是单规则属性选择器的规则。&lt;/p&gt;
&lt;h4 align=&quot;left&quot;&gt;避免类正则的属性选择器&lt;/h4&gt;
&lt;p align=&quot;left&quot;&gt;CSS3添加了复杂的属性选择器，可以通过类正则表达式的方式对元素的属性值进行匹配。当然这些类型的选择器定是会影响性能的，正则表达式匹配会比基于类别的匹配会慢很多。大部分情况下我们应尽量避免使用 *=， |=， ^=， $=， 和 ~=语法的属性选择器。&lt;/p&gt;
&lt;h4 align=&quot;left&quot;&gt;移除无匹配的样式&lt;/h4&gt;
&lt;p align=&quot;left&quot;&gt;移除无匹配的样式，有两个好处：&lt;/p&gt;
&lt;p align=&quot;left&quot;&gt;第一，删除无用的样式后可以缩减样式文件的体积，加快资源下载速度；&lt;/p&gt;
&lt;p align=&quot;left&quot;&gt;第二，对于浏览器而言，所有的样式规则的都会被解析后索引起来，即使是当前页面无匹配的规则。移除无匹配的规则，减少索引项，加快浏览器查找速度；&lt;/p&gt;

&lt;h2 id=&quot;高性能-javascript&quot;&gt;高性能 JavaScript&lt;/h2&gt;

&lt;h4 align=&quot;left&quot;&gt;使用事件代理&lt;/h4&gt;
&lt;p align=&quot;left&quot;&gt;有时候我们会感觉到页面反应迟钝，这是因为DOM树元素中附加了过多的事件句柄并且些事件句病被频繁地触发。这就是为什么说使用事件代理是一种好方法了。如果你在一个div中有10个按钮，你只需要在div上附加一次事件句柄就可以了，而不用去为每一个按钮增加一个句柄。事件冒泡时你可以捕捉到事件并判断出是哪个事件发出的。&lt;/p&gt;
&lt;h4 align=&quot;left&quot;&gt;&lt;span id=&quot;more-1625&quot;&gt;&lt;/span&gt;缓存选择器查询结果&lt;/h4&gt;
&lt;p align=&quot;left&quot;&gt;选择器查询是开销很大的方法。所以，使用选择器的次数应该越少越好，并且尽可能缓存选中的结果，便于以后反复使用。比如，下面这样的写法就是糟糕的写法：&lt;/p&gt;
&lt;pre&gt;jQuery(&apos;#top&apos;).find(&apos;p.classA&apos;);
jQuery(&apos;#top&apos;).find(&apos;p.classB&apos;);&lt;/pre&gt;
&lt;p align=&quot;left&quot;&gt;更好的写法是：&lt;/p&gt;
&lt;pre&gt;var cached = jQuery(&apos;#top&apos;); cached.find(&apos;p.classA&apos;); cached.find(&apos;p.classB&apos;);&lt;/pre&gt;
&lt;h4 align=&quot;left&quot;&gt;避免频繁的IO操作&lt;/h4&gt;
&lt;p align=&quot;left&quot;&gt;对 cookie 与 localstorage 操作的API是同步的，且cookie与localstorage是多个tab页面间共享的，多页面同时操作时会存在同步加锁机制，建议应尽量少的对cookie或localStorage进行操作。&lt;/p&gt;
&lt;h4 align=&quot;left&quot;&gt;避免频繁的DOM操作&lt;/h4&gt;
&lt;p align=&quot;left&quot;&gt;使用JavaScript访问DOM元素是比较慢的，因此为了提升性能，应该做到：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;缓存已经查询过的元素；&lt;/li&gt;
&lt;li&gt;线下更新完节点之后再将它们添加到文档树中；&lt;/li&gt;
&lt;li&gt;避免使用JavaScript来修改页面布局；&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 align=&quot;left&quot;&gt;使用微类库&lt;/h4&gt;
&lt;p align=&quot;left&quot;&gt;通常开发者都会使用JavaScript类库，如jQuery、Mootools、YUI、Dojo等，但是开发者往往只是使用JavaScript类库中的部分功能。为了更大的提升性能，应尽量避免使用这类大而全的类库，而是按需使用微类库来辅助开发。&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Javascript 浮点运算问题分析与解决</title>
   <link href="https://yuanyan.github.io/javascript/javscript-float-number-compute-problem"/>
   <updated>2010-10-16T00:00:00+00:00</updated>
   <id>hhttps://yuanyan.github.io/javascript/javscript-float-number-compute-problem</id>
   <content type="html">
&lt;h2 id=&quot;分析&quot;&gt;分析&lt;/h2&gt;

&lt;p&gt;JavaScript 只有一种数字类型 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Number&lt;/code&gt; ，而且在Javascript中所有的数字都是以&lt;a href=&quot;http://zh.wikipedia.org/zh-cn/IEEE_754&quot;&gt;IEEE-754&lt;/a&gt;标准格式表示的。
浮点数的精度问题不是JavaScript特有的，因为有些小数以二进制表示位数是无穷的：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;十进制           二进制
0.1              0.0001 1001 1001 1001 ...
0.2              0.0011 0011 0011 0011 ...
0.3              0.0100 1100 1100 1100 ...
0.4              0.0110 0110 0110 0110 ...
0.5              0.1
0.6              0.1001 1001 1001 1001 ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;所以比如 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1.1&lt;/code&gt; ，其程序实际上无法真正的表示 ‘1.1’，而只能做到一定程度上的准确,这是无法避免的精度丢失：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;1.09999999999999999
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;在JavaScript中问题还要复杂些，这里只给一些在Chrome中测试数据：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; 输入               输出
1.0-0.9 == 0.1     False
1.0-0.8 == 0.2     False
1.0-0.7 == 0.3     False
1.0-0.6 == 0.4     True
1.0-0.5 == 0.5     True
1.0-0.4 == 0.6     True
1.0-0.3 == 0.7     True
1.0-0.2 == 0.8     True
1.0-0.1 == 0.9     True
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;解决&quot;&gt;解决&lt;/h2&gt;

&lt;p&gt;那如何来避免这类 ` 1.0-0.9 != 0.1 ` 的非bug型问题发生呢？下面给出一种目前用的比较多的解决方案,
在判断浮点运算结果前对计算结果进行精度缩小，因为在精度缩小的过程总会自动四舍五入:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;(1.0-0.9).toFixed(digits)                   // toFixed() 精度参数须在 0 与20 之间
parseFloat((1.0-0.9).toFixed(10)) === 0.1   // 结果为True
parseFloat((1.0-0.8).toFixed(10)) === 0.2   // 结果为True
parseFloat((1.0-0.7).toFixed(10)) === 0.3   // 结果为True
parseFloat((11.0-11.8).toFixed(10)) === -0.8   // 结果为True
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;方法提炼&quot;&gt;方法提炼&lt;/h2&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;// 通过isEqual工具方法判断数值是否相等
function isEqual(number1, number2, digits){
	digits = digits == undefined? 10: digits; // 默认精度为10
	return number1.toFixed(digits) === number2.toFixed(digits);
}

isEqual(1.0-0.7, 0.3);  // return true

// 原生扩展方式，更喜欢面向对象的风格
Number.prototype.isEqual = function(number, digits){
	digits = digits == undefined? 10: digits; // 默认精度为10
	return this.toFixed(digits) === number.toFixed(digits);
}

(1.0-0.7).isEqual(0.3); // return true
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</content>
 </entry>
 
 
</feed>