<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>百度泛用户体验</title>
	<atom:link href="http://www.baiduux.com/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.baiduux.com/blog</link>
	<description>Just another WordPress weblog</description>
	<lastBuildDate>Wed, 29 Feb 2012 09:42:50 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Flash持续集成自动化单元测试</title>
		<link>http://www.baiduux.com/blog/2012/02/06/flash-ci-and-testing/</link>
		<comments>http://www.baiduux.com/blog/2012/02/06/flash-ci-and-testing/#comments</comments>
		<pubDate>Mon, 06 Feb 2012 07:12:01 +0000</pubDate>
		<dc:creator>Leon</dc:creator>
				<category><![CDATA[Flash]]></category>

		<guid isPermaLink="false">http://www.baiduux.com/blog/?p=1203</guid>
		<description><![CDATA[本文关注于宏观上的CI和单元测试技术，某些技术上的具体细节会略过，更多细节请参考最后部分的“参考资料”及文中的链接。
作者：杜明坦
本文包括：持续集成、单元测试、Mock技术、Case选取策略和示例等五部分
持续集成(CI)
CI是一种实践，旨在缓和和稳固软件的构建过程，能够应对如下挑战：

软件构建自动化
持续自动的构建检查
持续自动的构建测试（本篇文章的重点所在）
构建生成后续过程的自动化


详情见：
 http://www.javaworld.com/javaworld/jw-12-2008/jw-12-hudson-ci.html

hudson及搭建
一个非常流行的CI工具，易于安装及配置，学习成本低，本篇中hudson安装及配置在windows平台进行。
安装JDK
从www.java.com下载直接安装，然后设置java相关的环境变量：

JAVA_HOME：jdk安装目录，例如：c:\java\jdk1.7.0
PATH：使得系统在任何路径下可以识别java命令，设为：%JAVA_HOME%/bin;%JAVA_HOME%/jre/bin
CLASSPATH：为java加载类(class or lib)路径，只有类在classpath中，java命令才能识别，设为：.;%JAVA_HOME%/lib/dt.jar;%JAVA_HOME%/lib/tools.jar (要加.表示当前路径)

安装ANT

从http://ant.apache.org/下载ant1.8.2
解压到任意目录，设置环境变量ANT_HOME指向ant主目录
设置环境变量ANT_OPTS,值为-XX:MaxPermSize=128M -Xms128M -Xmx512M分配更大的内存空间

安装Hudson

首先下载hudson.war  http://www.hudson-ci.org/
其次通过 java -jar hudson.war命令运行
由于本身内置http服务，在浏览器中打开http://localhost:8080查看hudson是否运行
持续运行方法

简明使用方法
添加节点并进行设置
可以理解为一个项目，以下为admaker为例。 需要更多节点，请点击”New Node

节点设置，主要设置”Remote FS root”和“Launch Method”即可。

添加job并进行设置
可以理解为创建项目的一个任务,例子为auto，使用下图选项即可：

集成flexunit/pmd/cpd
hudnson通过ant进行自动化编译，把编译的结果设置为hudson的读取源，运行原理如下：

自动化编译设置
拷贝sdk\x.x.x\ant\lib下的flexTasks.jar至ant\lib目录下，并在build.xml中通过以下指令指定：
&#60;taskdef resource=&#34;flexTasks.tasks&#34; classpath=&#34;${FLEX_HOME}/ant/lib/flexTasks.jar&#34; /&#62;
单元测试所需文件设置
从https://github.com/flexunit/flexunit下载源代码，通过ant进行自动化编译，生成类似flexUnitTasks-4.1.0-x.jar的文件，拷贝到 项目所在的libs文件夹，并在build.xml中通过以下指令指定:
&#60;taskdef resource=&#34;flexUnitTasks.tasks&#34;&#62;
&#60;classpath&#62; 
&#60;fileset dir=&#34;${lib.loc}&#34;&#62; 
&#60;include name=&#34;flexUnitTasks*.jar&#34; /&#62; 
&#60;/fileset&#62; 
&#60;/classpath&#62; 
&#60;/taskdef&#62;&#34;
PMD/CPD
flexpmd，主要用来提升Flex/AS3源文件中的代码质量并且检测常见的不好的代码实践，比如无用的代码，效率低的代码片段，过于复杂的代码等等这些都是FlexPMD检测并报告的对象。
flexcpd，Flex/as3源文件中的代码重复率检查工具。 下载利用ant编译所需要的文件，最新版为1.2：http://opensource.adobe.com/wiki/display/flexpmd/Downloads
配置（flexpmd）：http://opensource.adobe.com/wiki/display/flexpmd/How+to+invoke+FlexPMD
配置（flexcpd）：http://opensource.adobe.com/wiki/display/flexpmd/FlexCPD
条件编译参数的方法
在flex-config.xml文件中的&#60;compile&#62;&#60;/compile&#62;中添加以下内容：
&#60;define&#62; 
&#60;name&#62;CONFIG::debug&#60;/name&#62; 
&#60;value&#62;false&#60;/value&#62; 
&#60;/define&#62; 
&#60;define&#62; 
&#60;name&#62;CONFIG::embed&#60;/name&#62; 
&#60;value&#62;false&#60;/value&#62; 
&#60;/define&#62; 
&#60;define&#62; 
&#60;name&#62;CONFIG::edit&#60;/name&#62; 
&#60;value&#62;true&#60;/value&#62; 
&#60;/define&#62;
构建
点击“Build Now”即可看到相应结果

windows下默认端口1024被占用问题
中的属性port是指定socket server的端口号，而CIListener中的默认端口号是1024，此时需要做的是：
修改CIListener.as和VisualDebuggerListener.mxml中的默认端口号为9900,在flexunit项目目录中执行ant编译，在FlexUnit4Test\libs中找到flexunit-cilistener-41.0-1-4.5.0.0.swc文件，放到你的项目相应的地方即可，此时要注意显示指定port=&#8221;9900&#8243;。
为了不显示指定端口号9900,需在TestRunConfiguration.java中修改默认端口号为9900，在flex项目目录中执行ant编译，在FlexUnit4Test\libs\build中找到flexUnitTasks-4.1.0-1.jar文件，放到你的项目的相应的位置即可。  建议把完成以上两个步骤的操作
单元测试
flexunit4
进化史
as2unit 2003
flex1.0 flexunit
flex2.0 flexunit.9 as3—&#62; as3flexunit(google code)—–&#62;back to adobe
dpUInt—〉Fluint
flexunit4 2009
框架原理图

使用方法

在项目上点击右键，添加test case [...]]]></description>
			<content:encoded><![CDATA[<p>本文关注于宏观上的CI和单元测试技术，某些技术上的具体细节会略过，更多细节请参考最后部分的“参考资料”及文中的链接。</p>
<p>作者：杜明坦</p>
<p>本文包括：持续集成、单元测试、Mock技术、Case选取策略和示例等五部分</p>
<h2>持续集成(CI)</h2>
<p>CI是一种实践，旨在缓和和稳固软件的构建过程，能够应对如下挑战：</p>
<ul>
<li>软件构建自动化</li>
<li>持续自动的构建检查</li>
<li>持续自动的构建测试（<strong>本篇文章的重点所在</strong>）</li>
<li>构建生成后续过程的自动化</li>
</ul>
<p><img src="http://i.6.cn/cvbnm/ed/6c/e6/c9f5bc34fb2a4497bedb9411caadc6a0.jpg" alt="持续集成示意图" /></p>
<p>详情见：<br />
 <a href="http://www.javaworld.com/javaworld/jw-12-2008/jw-12-hudson-ci.html">http://www.javaworld.com/javaworld/jw-12-2008/jw-12-hudson-ci.html</a></p>
<p><span id="more-1203"></span></p>
<h3>hudson及搭建</h3>
<p>一个非常流行的CI工具，易于安装及配置，学习成本低，本篇中hudson安装及配置在windows平台进行。</p>
<h4>安装JDK</h4>
<p>从<a href="http://www.java.com/"><span style="font-size: small">www.java.com</span></a>下载直接安装，然后设置java相关的环境变量：</p>
<ul>
<li>JAVA_HOME：jdk安装目录，例如：c:\java\jdk1.7.0</li>
<li>PATH：使得系统在任何路径下可以识别java命令，设为：%JAVA_HOME%/bin;%JAVA_HOME%/jre/bin</li>
<li>CLASSPATH：为java加载类(class or lib)路径，只有类在classpath中，java命令才能识别，设为：.;%JAVA_HOME%/lib/dt.jar;%JAVA_HOME%/lib/tools.jar (要加.表示当前路径)</li>
</ul>
<h3>安装ANT</h3>
<ol>
<li>从<a href="http://ant.apache.org/">http://ant.apache.org/</a>下载ant1.8.2</li>
<li>解压到任意目录，设置环境变量ANT_HOME指向ant主目录</li>
<li>设置环境变量ANT_OPTS,值为-XX:MaxPermSize=128M -Xms128M -Xmx512M分配更大的内存空间</li>
</ol>
<h3>安装Hudson</h3>
<ol>
<li>首先下载hudson.war  <a href="http://www.hudson-ci.org/" target="_blank">http://www.hudson-ci.org/</a></li>
<li>其次通过 java -jar hudson.war命令运行</li>
<li>由于本身内置http服务，在浏览器中打开http://localhost:8080查看hudson是否运行</li>
<li>持续运行方法</li>
</ol>
<h3>简明使用方法</h3>
<h4>添加节点并进行设置</h4>
<p>可以理解为一个项目，以下为admaker为例。 需要更多节点，请点击”New Node</p>
<p><img src="http://i.6.cn/cvbnm/73/c6/d1/67fe15eba20ceffb4eda3c9dbbb6078e.png" alt="Hudson新建节点" /></p>
<p>节点设置，主要设置”Remote FS root”和“Launch Method”即可。</p>
<p><img src="http://i.6.cn/cvbnm/41/64/00/98aec31f236483aba2baf7cc523918f7.png" alt="节点设置" /></p>
<h3>添加job并进行设置</h3>
<p>可以理解为创建项目的一个任务,例子为auto，使用下图选项即可：</p>
<p><img src="http://i.6.cn/cvbnm/e2/fa/57/b64a580fa03181832a82a4312aa8d15a.png" alt="Job设置" /></p>
<h3>集成flexunit/pmd/cpd</h3>
<p>hudnson通过ant进行自动化编译，把编译的结果设置为hudson的读取源，运行原理如下：</p>
<p><img src="http://i.6.cn/cvbnm/e1/7e/18/47ed817402d13e9f4fe57fe2b68c3267.png" alt="运行原理" /></p>
<h4>自动化编译设置</h4>
<p>拷贝sdk\x.x.x\ant\lib下的flexTasks.jar至ant\lib目录下，并在build.xml中通过以下指令指定：</p>
<div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;taskdef</span> <span style="color: #000066;">resource</span>=<span style="color: #ff0000;">&quot;flexTasks.tasks&quot;</span> <span style="color: #000066;">classpath</span>=<span style="color: #ff0000;">&quot;${FLEX_HOME}/ant/lib/flexTasks.jar&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span></div></div>
<h4>单元测试所需文件设置</h4>
<p>从<a href="https://github.com/flexunit/flexunit">https://github.com/flexunit/flexunit</a>下载源代码，通过ant进行自动化编译，生成类似flexUnitTasks-4.1.0-x.jar的文件，拷贝到 项目所在的libs文件夹，并在build.xml中通过以下指令指定:</p>
<div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;taskdef</span> <span style="color: #000066;">resource</span>=<span style="color: #ff0000;">&quot;flexUnitTasks.tasks&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;classpath<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> <br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;fileset</span> <span style="color: #000066;">dir</span>=<span style="color: #ff0000;">&quot;${lib.loc}&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span> <br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;include</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;flexUnitTasks*.jar&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span> <br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/fileset<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> <br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/classpath<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> <br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/taskdef<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>&quot;</div></div>
<h4>PMD/CPD</h4>
<p>flexpmd，主要用来提升Flex/AS3源文件中的代码质量并且检测常见的不好的代码实践，比如无用的代码，效率低的代码片段，过于复杂的代码等等这些都是FlexPMD检测并报告的对象。</p>
<p>flexcpd，Flex/as3源文件中的代码重复率检查工具。 下载利用ant编译所需要的文件，最新版为1.2：<a href="http://opensource.adobe.com/wiki/display/flexpmd/Downloads">http://opensource.adobe.com/wiki/display/flexpmd/Downloads</a></p>
<p>配置（flexpmd）：<a href="http://opensource.adobe.com/wiki/display/flexpmd/How+to+invoke+FlexPMD">http://opensource.adobe.com/wiki/display/flexpmd/How+to+invoke+FlexPMD</a></p>
<p>配置（flexcpd）：<a href="http://opensource.adobe.com/wiki/display/flexpmd/FlexCPD">http://opensource.adobe.com/wiki/display/flexpmd/FlexCPD</a></p>
<h4>条件编译参数的方法</h4>
<p>在flex-config.xml文件中的&lt;compile&gt;&lt;/compile&gt;中添加以下内容：</p>
<div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;define<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> <br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>CONFIG::debug<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> <br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;value<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>false<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/value<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> <br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/define<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> <br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;define<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> <br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>CONFIG::embed<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> <br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;value<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>false<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/value<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> <br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/define<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> <br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;define<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> <br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>CONFIG::edit<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/name<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> <br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;value<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>true<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/value<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> <br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/define<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></div>
<h3>构建</h3>
<p>点击“Build Now”即可看到相应结果</p>
<p><img src="http://i.6.cn/cvbnm/62/49/0f/71ac6cf64c60751a629f269f799474be.png" alt="Build结果" /></p>
<h3>windows下默认端口1024被占用问题</h3>
<p>中的属性port是指定socket server的端口号，而CIListener中的默认端口号是1024，此时需要做的是：</p>
<p>修改CIListener.as和VisualDebuggerListener.mxml中的默认端口号为9900,在flexunit项目目录中执行ant编译，在FlexUnit4Test\libs中找到flexunit-cilistener-41.0-1-4.5.0.0.swc文件，放到你的项目相应的地方即可，此时要注意显示指定port=&#8221;9900&#8243;。</p>
<p>为了不显示指定端口号9900,需在TestRunConfiguration.java中修改默认端口号为9900，在flex项目目录中执行ant编译，在FlexUnit4Test\libs\build中找到flexUnitTasks-4.1.0-1.jar文件，放到你的项目的相应的位置即可。  建议把完成以上两个步骤的操作</p>
<h2>单元测试</h2>
<h3>flexunit4</h3>
<h4>进化史</h4>
<p>as2unit 2003</p>
<p>flex1.0 flexunit</p>
<p>flex2.0 flexunit.9 as3—&gt; as3flexunit(google code)—–&gt;back to adobe</p>
<p>dpUInt—〉Fluint</p>
<p>flexunit4 2009</p>
<h4>框架原理图</h4>
<p><img src="http://i.6.cn/cvbnm/9e/4c/a5/3a1dba73c2b7575c9e7c92c65281d752.png" alt="框架原理" /></p>
<h4>使用方法</h4>
<ol>
<li>在项目上点击右键，添加test case 或test suite(为case套装，包含n个case)，添加相应的文件，flash builder会为你自动创建测试用主类FlexUnitApplication.as</li>
<li>在项目上点击右键“执行单元测试”或通过单元测试面板执行，选择相应的test case 或者test suite运行即可。</li>
<li>一般的结构如下，把AM2Test作为唯一的入口即可：<br />
 <img src="http://i.6.cn/cvbnm/91/25/d2/fef431ca68dcd0c5446e6f5f7373ab38.png" alt="" /> </li>
</ol>
<h3>基础知识</h3>
<h4>testMethod,testCase,testSuite</h4>
<p>结构图如下： <img src="http://i.6.cn/cvbnm/72/8d/af/079531e310b4bcb7406c26ffaf76ea02.png" alt="测试示意图" /></p>
<h4>testMethod</h4>
<p>最小的测试单元，顾名思义，针对类的方法的测试，使用[Test]元标签，示例如下：</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp;<span style="color: #009900;">&#91;</span>Test<span style="color: #009900;">&#93;</span><br />
&nbsp;<span style="color: #003366; font-weight: bold;">public</span> <span style="color: #003366; font-weight: bold;">function</span> testUpload<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span></div></div>
<p>策略:</p>
<ol>
<li>一般为要至少为类中的每个方法写一个testMethod</li>
<li>对于一个方法，由于不同的条件逻辑可能会产生不同的结果，针对每一个结果写一个testMethod</li>
<li>针对没一个方法，写两个testMethod，针对有效和无效的输入</li>
</ol>
<h4>TestCase</h4>
<p>testMethod的集合，测试多个相关的功能点，一般针对某一个类，其中包含所有的需要测试的testMethod,包含如下特有的元数据标签,可以重复书写：</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&#91;</span>Before<span style="color: #009900;">&#93;</span><br />
<span style="color: #009900;">&#91;</span>Before <span style="color: #003366; font-weight: bold;">Class</span><span style="color: #009900;">&#93;</span><br />
<span style="color: #009900;">&#91;</span>After<span style="color: #009900;">&#93;</span><br />
<span style="color: #009900;">&#91;</span>After <span style="color: #003366; font-weight: bold;">Class</span><span style="color: #009900;">&#93;</span><br />
<span style="color: #009900;">&#91;</span>Test<span style="color: #009900;">&#93;</span></div></div>
<p>其中每个[Test]是可以有顺序的，通过order属性指定，形如：</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&#91;</span>Test<span style="color: #009900;">&#40;</span>order<span style="color: #339933;">=</span>1<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#93;</span><br />
<span style="color: #003366; font-weight: bold;">public</span> <span style="color: #003366; font-weight: bold;">function</span> testOrder1<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#91;</span>Test<span style="color: #009900;">&#40;</span>order<span style="color: #339933;">=</span>2<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#93;</span><br />
<span style="color: #003366; font-weight: bold;">public</span> <span style="color: #003366; font-weight: bold;">function</span> testOrder2<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span></div></div>
<h4>TestSuite</h4>
<p>testCase的集合，使用如下元数据标签标记，示例如下：</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&#91;</span>Suite<span style="color: #009900;">&#93;</span><br />
<span style="color: #009900;">&#91;</span>RunWith<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;org.flexunit.runners.Suite&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#93;</span><br />
<span style="color: #003366; font-weight: bold;">public</span> <span style="color: #003366; font-weight: bold;">class</span> MultiFileUploaderSuite<span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp;<span style="color: #003366; font-weight: bold;">public</span> <span style="color: #003366; font-weight: bold;">var</span> _testUploadList<span style="color: #339933;">:</span>TestUploadList<span style="color: #339933;">;</span><br />
&nbsp;<span style="color: #009900;">&#125;</span></div></div>
<h3>断言</h3>
<p>断言用于比较测试目标的结果和预期值，一般格式如下：</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">assert<span style="color: #009900;">&#40;</span> <span style="color: #3366CC;">&quot;错误提示&quot;</span><span style="color: #339933;">,</span> 预期值， 实际值 <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<p>示例：</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">result <span style="color: #339933;">=</span> 1 <span style="color: #339933;">+</span> <span style="color: #CC0000;">2</span><span style="color: #339933;">;</span><br />
assertEqual<span style="color: #009900;">&#40;</span> <span style="color: #3366CC;">&quot;结果不为3&quot;</span><span style="color: #339933;">,</span> 3<span style="color: #339933;">,</span> result <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<p>有两种使用格式：</p>
<h3>hamcrest</h3>
<p>开源的匹配器库，格式如下：</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">assertThat<span style="color: #009900;">&#40;</span> value<span style="color: #339933;">,</span> matcher <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<p>其中，matcher是一个类，有is(),between(),closeTo()等</p>
<p>用法举例：</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">assertThat<span style="color: #009900;">&#40;</span> num1<span style="color: #339933;">,</span> <span style="color: #000066; font-weight: bold;">is</span><span style="color: #009900;">&#40;</span> between<span style="color: #009900;">&#40;</span> num2<span style="color: #339933;">,</span> num3 <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<p>自定义matcher:</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #003366; font-weight: bold;">import</span> org.<span style="color: #660066;">hamcrest</span>.<span style="color: #660066;">TypeSafeMatcher</span><span style="color: #339933;">;</span><br />
<span style="color: #003366; font-weight: bold;">import</span> org.<span style="color: #660066;">hamcrest</span>.<span style="color: #660066;">Description</span><span style="color: #339933;">;</span><br />
<span style="color: #003366; font-weight: bold;">public</span> <span style="color: #003366; font-weight: bold;">class</span> myMatcher exends TypeSafeMatcher<span style="color: #009900;">&#123;</span><br />
<span style="color: #003366; font-weight: bold;">public</span> <span style="color: #003366; font-weight: bold;">function</span> myMatcher<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span><br />
override <span style="color: #003366; font-weight: bold;">public</span> <span style="color: #003366; font-weight: bold;">function</span> matchesSafely<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">item</span><span style="color: #339933;">:</span>Object<span style="color: #009900;">&#41;</span><span style="color: #339933;">:</span>Boolean <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span><br />
override <span style="color: #003366; font-weight: bold;">public</span> <span style="color: #003366; font-weight: bold;">function</span> describeTo<span style="color: #009900;">&#40;</span>description<span style="color: #339933;">:</span>Description<span style="color: #009900;">&#41;</span><span style="color: #339933;">:</span><span style="color: #000066; font-weight: bold;">void</span> <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>更多内容见：<a href="http://github.com/drewbourne/hamcrest-as3" target="_blank">http://github.com/drewbourne/hamcrest-as3</a></p>
<h3>异步测试</h3>
<p>flexunit4的核心功能，想想flash中的各种异步事件吧！包含两种格式，事件处理和事件序列（sequence）。</p>
<p>事件处理示例代码：</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&#91;</span>Test<span style="color: #009900;">&#40;</span>async<span style="color: #339933;">,</span> timeout<span style="color: #339933;">=</span>5000<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#93;</span><br />
<span style="color: #003366; font-weight: bold;">public</span> <span style="color: #003366; font-weight: bold;">function</span> testCancel<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">:</span><span style="color: #000066; font-weight: bold;">void</span><span style="color: #009900;">&#123;</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> mHandler<span style="color: #339933;">:</span><span style="color: #003366; font-weight: bold;">Function</span> <span style="color: #339933;">=</span> Async.<span style="color: #660066;">asyncHandler</span><span style="color: #009900;">&#40;</span> <span style="color: #000066; font-weight: bold;">this</span><span style="color: #339933;">,</span> cancelHandler<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp;<span style="color: #CC0000;">5000</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#123;</span>num<span style="color: #339933;">:</span><span style="color: #CC0000;">4</span><span style="color: #339933;">,</span>type<span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;m&quot;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> timeoutHandler <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp;<br />
&nbsp; &nbsp; _uploader.<span style="color: #660066;">addEventListener</span><span style="color: #009900;">&#40;</span> UploaderEvent.<span style="color: #660066;">EVENT_FILE_ALL_MEMEORY</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp;mHandler <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; _uploader.<span style="color: #660066;">loadtoMemory</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; <br />
<span style="color: #009900;">&#125;</span></div></div>
<p>如示例所示：</p>
<ul>
<li>async:必须存在，说明是异步测试</li>
<li>timeout=5000, 在5000毫秒内测试未完成，默认超时处理</li>
</ul>
<p>mHandle是异步处理对象，包含5个参数，意义如下：</p>
<ul>
<li>this:针对哪个TestCase，这里即为this</li>
<li>cancelHandler,接收到UploaderEvent.EVENT_FILE_ALL_MEMORY事件后触发的事件对象</li>
<li>5000，超时处理触发的最大时间</li>
<li>{num:4,type:&#8221;m&#8221;},传递给cancelHandler对象的参数</li>
<li>timeoutHandler,超时处理对象，5000ms后未触发cancelHandler对象触发</li>
</ul>
<p>更多内容见：<a href="http://docs.flexunit.org/index.php?title=Writing_an_Async_setup#Approach" target="_blank">更多内容见：http://docs.flexunit.org/index.php?title=Writing_an_Async_setup#Approach</a></p>
<p>事件序列，是一个很实用的使用格式，例如测试一个文件上传过程中取消的功能，会触发的事件有上传，取消成功，取消失败等，这个时候假如用事件处理的格式书写的话，会涉及到n个处理函数，很复杂，而用sequence呢，显然一目了然。</p>
<p>事件序列示例代码：</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&#91;</span>Test<span style="color: #009900;">&#40;</span> async <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#93;</span><br />
<span style="color: #003366; font-weight: bold;">public</span> <span style="color: #003366; font-weight: bold;">function</span> shouldCompleteTimerSequence<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">:</span><span style="color: #000066; font-weight: bold;">void</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #003366; font-weight: bold;">var</span> timer<span style="color: #339933;">:</span>Timer <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">new</span> Timer<span style="color: #009900;">&#40;</span> TIMEOUT <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> sequence<span style="color: #339933;">:</span>SequenceRunner <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">new</span> SequenceRunner<span style="color: #009900;">&#40;</span> <span style="color: #000066; font-weight: bold;">this</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; sequence.<span style="color: #660066;">addStep</span><span style="color: #009900;">&#40;</span> <span style="color: #003366; font-weight: bold;">new</span> SequenceCaller<span style="color: #009900;">&#40;</span> timer<span style="color: #339933;">,</span> timer.<span style="color: #660066;">start</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; sequence.<span style="color: #660066;">addStep</span><span style="color: #009900;">&#40;</span> <span style="color: #003366; font-weight: bold;">new</span> SequenceWaiter<span style="color: #009900;">&#40;</span> timer<span style="color: #339933;">,</span> TimerEvent.<span style="color: #660066;">TIMER</span><span style="color: #339933;">,</span> TIMEOUT2 <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; sequence.<span style="color: #660066;">addStep</span><span style="color: #009900;">&#40;</span> <span style="color: #003366; font-weight: bold;">new</span> SequenceWaiter<span style="color: #009900;">&#40;</span> timer<span style="color: #339933;">,</span> TimerEvent.<span style="color: #660066;">TIMER</span><span style="color: #339933;">,</span> TIMEOUT2 <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; sequence.<span style="color: #660066;">addStep</span><span style="color: #009900;">&#40;</span> <span style="color: #003366; font-weight: bold;">new</span> SequenceWaiter<span style="color: #009900;">&#40;</span> timer<span style="color: #339933;">,</span> TimerEvent.<span style="color: #660066;">TIMER</span><span style="color: #339933;">,</span> TIMEOUT2 <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; sequence.<span style="color: #660066;">addStep</span><span style="color: #009900;">&#40;</span> <span style="color: #003366; font-weight: bold;">new</span> SequenceCaller<span style="color: #009900;">&#40;</span> timer<span style="color: #339933;">,</span> timer.<span style="color: #000066;">stop</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; sequence.<span style="color: #660066;">addAssertHandler</span><span style="color: #009900;">&#40;</span> handleSequenceComplete<span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">null</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; sequence.<span style="color: #660066;">run</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>如示例所示，执行步骤如下：</p>
<ul>
<li>开始一个定时器</li>
<li>循环执行三次</li>
<li>停止定时器</li>
<li>执行断言</li>
</ul>
<p>更多内容见：<a href="http://docs.flexunit.org/index.php?title=Fluint_Sequences" target="_blank">更多内容见：http://docs.flexunit.org/index.php?title=Fluint_Sequences</a></p>
<h3>Rules</h3>
<p>类似于[Before]和[After]的元数据标签，提供更多高级功能，定义每个test运行前后的规则，在每个test之前和之后运行，结构如下：</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">-BeforeClasses<br />
&nbsp; &nbsp; -Rules<br />
&nbsp; &nbsp; -Befores<br />
&nbsp; &nbsp; &nbsp; &nbsp; -Test<br />
&nbsp; &nbsp; -Afters<br />
&nbsp; &nbsp; -Rules (the same ones as above)<br />
-AfterClasses</div></div>
<h3>UIImpersonator</h3>
<p>借鉴Fluint框架的测试内容的显示对象，通过它你可以把可视化的内容暂时在舞台上，其实个人认为实用性不大，和自动化的思想有违背。在纯as3项目中暂时无法显示，不过可以利用这个技巧实现：https://gist.github.com/1094408 </p>
<p><a href="http://docs.flexunit.org/index.php?title=UIImpersonator" target="_blank">更多内容见：http://docs.flexunit.org/index.php?title=UIImpersonator</a></p>
<h3>Runner和自定义Runner</h3>
<p>规定了Test Method、Test  Case和Test Suite运行时的行为，兼容性好，能很好的运行flexunit1和fluint框架的测试内容。有不同责任的Runner，最常用的就是Suite。当测试单元运行的时候，ClassRequest对象会根据每个Test Case和Test Suite的内容进行包装成为IRequest对象，并为此对象构建相应的Runner，FlexUnitCore.run( ClassRequest)会执行所有的IRequest对象，触发IRequest的run()方法，执行相应的Runner.run()。系统自定义的Runner有：</p>
<ul>
<li>IgnoredClassRunner</li>
<li>Suite</li>
<li>TheoryBlockRunner</li>
<li>SuiteMethod</li>
<li>FlexUnit1ClassRunner </li>
<li>Fluint1ClassRunner </li>
<li>BlockFlexUnit4ClassRunner  </li>
<li>ParentRunner </li>
</ul>
<p>要自定义Runner，可以实现以下方法：</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #003366; font-weight: bold;">import</span> org.<span style="color: #660066;">flexunit</span>.<span style="color: #660066;">runner</span>.<span style="color: #660066;">IDescription</span><span style="color: #339933;">;</span><br />
<span style="color: #003366; font-weight: bold;">import</span> org.<span style="color: #660066;">flexunit</span>.<span style="color: #660066;">runner</span>.<span style="color: #660066;">IRunner</span><span style="color: #339933;">;</span><br />
<span style="color: #003366; font-weight: bold;">import</span> org.<span style="color: #660066;">flexunit</span>.<span style="color: #660066;">runner</span>.<span style="color: #660066;">notification</span>.<span style="color: #660066;">IRunNotifier</span><span style="color: #339933;">;</span><br />
<span style="color: #003366; font-weight: bold;">import</span> org.<span style="color: #660066;">flexunit</span>.<span style="color: #660066;">token</span>.<span style="color: #660066;">IAsyncTestToken</span><span style="color: #339933;">;</span><br />
<span style="color: #003366; font-weight: bold;">public</span> <span style="color: #003366; font-weight: bold;">class</span> CustomRunner implements IRunner <span style="color: #009900;">&#123;</span><br />
<span style="color: #003366; font-weight: bold;">public</span> <span style="color: #003366; font-weight: bold;">function</span> CustomRunner<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span><br />
<span style="color: #003366; font-weight: bold;">public</span> <span style="color: #003366; font-weight: bold;">function</span> run<span style="color: #009900;">&#40;</span>notifier<span style="color: #339933;">:</span>IRunNotifier<span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; previousToken<span style="color: #339933;">:</span>IAsyncTestToken<span style="color: #009900;">&#41;</span><span style="color: #339933;">:</span><span style="color: #000066; font-weight: bold;">void</span> <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span><br />
<span style="color: #003366; font-weight: bold;">public</span> <span style="color: #003366; font-weight: bold;">function</span> get description<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">:</span>IDescription <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span><br />
<span style="color: #003366; font-weight: bold;">public</span> <span style="color: #003366; font-weight: bold;">function</span> pleaseStop<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">:</span><span style="color: #000066; font-weight: bold;">void</span> <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p><a href="http://docs.flexunit.org/index.php?title=Custom_Runners" target="_blank">更多内容见：http://docs.flexunit.org/index.php?title=Custom_Runners</a></p>
<h3>UIListener</h3>
<p>Runner的监听对象，对监听内容进行图形化表示，过程如下：</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #003366; font-weight: bold;">import</span> sampleSuite.<span style="color: #660066;">SampleSuite</span><span style="color: #339933;">;</span><br />
<span style="color: #003366; font-weight: bold;">import</span> org.<span style="color: #660066;">flexunit</span>.<span style="color: #660066;">listeners</span>.<span style="color: #660066;">UIListener</span><span style="color: #339933;">;</span><br />
<span style="color: #003366; font-weight: bold;">import</span> org.<span style="color: #660066;">flexunit</span>.<span style="color: #660066;">runner</span>.<span style="color: #660066;">FlexUnitCore</span><span style="color: #339933;">;</span><br />
<span style="color: #003366; font-weight: bold;">private</span> <span style="color: #003366; font-weight: bold;">var</span> core<span style="color: #339933;">:</span>FlexUnitCore<span style="color: #339933;">;</span><br />
<span style="color: #003366; font-weight: bold;">public</span> <span style="color: #003366; font-weight: bold;">function</span> runMe<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">:</span><span style="color: #000066; font-weight: bold;">void</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; core <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">new</span> FlexUnitCore<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; core.<span style="color: #660066;">addListener</span><span style="color: #009900;">&#40;</span> <span style="color: #003366; font-weight: bold;">new</span> UIListener<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; core.<span style="color: #660066;">run</span><span style="color: #009900;">&#40;</span> sampleSuite.<span style="color: #660066;">SampleSuite</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<h3>CIListener</h3>
<p>Runner的监听对象，不需要进行图形化的表示，说要做的就是把监听到的内容通过Socket发送给服务端，把内容写到磁盘，供Hudson读取处理，过程如下：</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">core.<span style="color: #660066;">addListener</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">new</span> CIListener<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
core.<span style="color: #660066;">run</span><span style="color: #009900;">&#40;</span> sampleSuite.<span style="color: #660066;">SampleSuite</span> <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#125;</span></div></div>
<h2>Mockolate</h2>
<h3>原理</h3>
<p>对象的一个代理对象，包含原对象的所有公共方法和属性，mock对象的父类为原对象类，这样就可以在使用原对象的地方使用mock对象。</p>
<p>由于mock技术是一门独立的技术，在此不作详述，请参考：<a href="http://www.mockolate.org/" target="_blank">http://www.mockolate.org/</a></p>
<h3>使用</h3>
<p>自定义Runner，自定义Rule，以及Mock标签：</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&#91;</span>RunWith<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;mockolate.runner.MockolateRunner&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#93;</span><br />
<span style="color: #003366; font-weight: bold;">public</span> <span style="color: #003366; font-weight: bold;">class</span> TestUploader<span style="color: #009900;">&#123;</span> &nbsp; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
<span style="color: #009900;">&#91;</span>Rule<span style="color: #009900;">&#93;</span><br />
<span style="color: #003366; font-weight: bold;">public</span> <span style="color: #003366; font-weight: bold;">var</span> mocks<span style="color: #339933;">:</span>MockolateRule <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">new</span> MockolateRule<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp;<br />
<span style="color: #009900;">&#91;</span>Mock<span style="color: #009900;">&#40;</span>type<span style="color: #339933;">=</span><span style="color: #3366CC;">&quot;strict&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#93;</span><br />
<span style="color: #003366; font-weight: bold;">public</span> <span style="color: #003366; font-weight: bold;">var</span> fileReference<span style="color: #339933;">:</span>FileReference<span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#91;</span>Mock<span style="color: #009900;">&#40;</span>type<span style="color: #339933;">=</span><span style="color: #3366CC;">&quot;strict&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#93;</span><br />
<span style="color: #003366; font-weight: bold;">public</span> <span style="color: #003366; font-weight: bold;">var</span> fileReferenceList<span style="color: #339933;">:</span>FileReferenceList<span style="color: #339933;">;</span> &nbsp; &nbsp;<br />
&nbsp;<br />
<span style="color: #009900;">&#125;</span></div></div>
<p>如上所示，在运行这个TestCase的时候使用MockolateRunner，自定义MockoateRule，通过Mock标签指定要mock的类，并指定为strict模式。</p>
<p>接下来做的是在TestMethod中使用它们：</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #003366; font-weight: bold;">var</span> frl<span style="color: #339933;">:</span>FileReferenceList <span style="color: #339933;">=</span> strict<span style="color: #009900;">&#40;</span> FileReferenceList <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
mock<span style="color: #009900;">&#40;</span> frl <span style="color: #009900;">&#41;</span>.<span style="color: #660066;">getter</span><span style="color: #009900;">&#40;</span> <span style="color: #3366CC;">&quot;fileList&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">returns</span><span style="color: #009900;">&#40;</span> <span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; &nbsp;<br />
mock<span style="color: #009900;">&#40;</span> frl <span style="color: #009900;">&#41;</span>.<span style="color: #660066;">method</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;toString&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">returns</span><span style="color: #009900;">&#40;</span> <span style="color: #3366CC;">&quot;FileReferenceList&quot;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
mock<span style="color: #009900;">&#40;</span> frl <span style="color: #009900;">&#41;</span>.<span style="color: #660066;">method</span><span style="color: #009900;">&#40;</span> <span style="color: #3366CC;">&quot;browse&quot;</span> <span style="color: #009900;">&#41;</span>.<span style="color: #660066;">args</span><span style="color: #009900;">&#40;</span> Array <span style="color: #009900;">&#41;</span>.<span style="color: #660066;">dispatches</span><span style="color: #009900;">&#40;</span> <span style="color: #003366; font-weight: bold;">new</span> Event<span style="color: #009900;">&#40;</span> Event.<span style="color: #660066;">SELECT</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">false</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; &nbsp;<br />
&nbsp;<br />
_uploader.<span style="color: #660066;">fileReferenceList</span> <span style="color: #339933;">=</span> frl<span style="color: #339933;">;</span></div></div>
<p>如上所示，<br />
getter方法fileList的返回为一个[]，</p>
<p>toString()方法返回“FileFeferenceList”，</p>
<p>调用browse()方法时，指定类型为Array的参数，并派发SELECT事件。</p>
<p>最后，通过_uploader.fileReferenceList = fr1，把Mock对象传递给_uploader对象。</p>
<h2>Case选择策略</h2>
<ul>
<li>针对接口，但不针对getter/setter方法</li>
<li>核心功能点，比如上传模块中的上传、中断等功能</li>
<li>逻辑复杂的功能点，if-else、switch-case等</li>
<li>针对功能点，可能组合各函数，在时间有限的情况下，非核心功能点可以省去</li>
<li>根据bug书写case，复现步骤，并验证之</li>
<li>不针对样式和展现等相关的功能点，例如，“当文件名为20个中文的时候，上传列表显示错乱”这样的问题，应完全由QA保证，属于非单测范围。</li>
<li>在单测开始之前，开发人员应和QA沟通确认哪些case是由QA保证，哪些case是由开发人员单测保证</li>
</ul>
<h3>示例展示</h3>
<p>以多文件上传核心类Uploader为例，要想测试此类必须要使用mock技术，因为FileReference的data为只读属性</p>
<p>根据选取策略，最终锁定在来Uploader类的核心方法，并建立如下的case：</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">testUploadedToMemory<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><br />
testUploadedALLComplete<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><br />
testUploadedALLError<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><br />
testCancel<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><br />
testResume<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><br />
testDelete<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span></div></div>
<p>每个case都会对FileReference、FileReferenceList和用于和AMF后端通讯的核心类AMFPHP进行mock，</p>
<p>testCancel()的示例代码如下：</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #006600; font-style: italic;">/**<br />
&nbsp;* 取消上传，上传完成2个后,cancel,验证以上传的ID列表的值是否为2<br />
* <br />
*/</span> &nbsp; &nbsp; &nbsp; &nbsp;<br />
<span style="color: #009900;">&#91;</span>Test<span style="color: #009900;">&#40;</span>async<span style="color: #339933;">,</span> order<span style="color: #339933;">=</span>4<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#93;</span><br />
<span style="color: #003366; font-weight: bold;">public</span> <span style="color: #003366; font-weight: bold;">function</span> testCancel<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">:</span><span style="color: #000066; font-weight: bold;">void</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; _count <span style="color: #339933;">=</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; mockFileReference<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; mockAMFPHP<span style="color: #009900;">&#40;</span> <span style="color: #003366; font-weight: bold;">true</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> mHandler<span style="color: #339933;">:</span><span style="color: #003366; font-weight: bold;">Function</span> <span style="color: #339933;">=</span> Async.<span style="color: #660066;">asyncHandler</span><span style="color: #009900;">&#40;</span> <span style="color: #000066; font-weight: bold;">this</span><span style="color: #339933;">,</span> cancelHandler<span style="color: #339933;">,</span> <span style="color: #CC0000;">5000</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#123;</span>num<span style="color: #339933;">:</span><span style="color: #CC0000;">4</span><span style="color: #339933;">,</span>type<span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;m&quot;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; timeoutHandler <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; _uploader.<span style="color: #660066;">addEventListener</span><span style="color: #009900;">&#40;</span> UploaderEvent.<span style="color: #660066;">EVENT_FILE_ALL_MEMEORY</span><span style="color: #339933;">,</span> mHandler <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; _uploader.<span style="color: #660066;">addFileType</span><span style="color: #009900;">&#40;</span> <span style="color: #3366CC;">&quot;test&quot;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; _uploader.<span style="color: #660066;">browse</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; &nbsp;<br />
<span style="color: #009900;">&#125;</span></div></div>
<p>FileReferenceHeFileReferenceList的mock代码：</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;height:300px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #006600; font-style: italic;">/**<br />
&nbsp;* mock reference相关的类 <br />
&nbsp;* <br />
&nbsp;*/</span> &nbsp; &nbsp; &nbsp; &nbsp;<br />
<span style="color: #003366; font-weight: bold;">private</span> <span style="color: #003366; font-weight: bold;">function</span> mockFileReference<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">:</span><span style="color: #000066; font-weight: bold;">void</span><span style="color: #009900;">&#123;</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> frl<span style="color: #339933;">:</span>FileReferenceList <span style="color: #339933;">=</span> strict<span style="color: #009900;">&#40;</span> FileReferenceList <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> num<span style="color: #339933;">:</span>int <span style="color: #339933;">=</span> <span style="color: #CC0000;">4</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> arr<span style="color: #339933;">:</span>Array <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">for</span><span style="color: #009900;">&#40;</span> <span style="color: #003366; font-weight: bold;">var</span> i<span style="color: #339933;">:</span>int<span style="color: #339933;">;</span> i <span style="color: #339933;">&amp;</span>lt<span style="color: #339933;">;</span> num<span style="color: #339933;">;</span> i<span style="color: #339933;">++</span> <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> fr<span style="color: #339933;">:</span>FileReference <span style="color: #339933;">=</span> strict<span style="color: #009900;">&#40;</span> FileReference <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; mock<span style="color: #009900;">&#40;</span> fr <span style="color: #009900;">&#41;</span>.<span style="color: #660066;">getter</span><span style="color: #009900;">&#40;</span> <span style="color: #339933;">&amp;</span>quot<span style="color: #339933;">;</span>data<span style="color: #339933;">&amp;</span>quot<span style="color: #339933;">;</span> <span style="color: #009900;">&#41;</span>.<span style="color: #660066;">returns</span><span style="color: #009900;">&#40;</span> _ba <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; mock<span style="color: #009900;">&#40;</span> fr <span style="color: #009900;">&#41;</span>.<span style="color: #660066;">getter</span><span style="color: #009900;">&#40;</span> <span style="color: #339933;">&amp;</span>quot<span style="color: #339933;">;</span>type<span style="color: #339933;">&amp;</span>quot<span style="color: #339933;">;</span> <span style="color: #009900;">&#41;</span>.<span style="color: #660066;">returns</span><span style="color: #009900;">&#40;</span> <span style="color: #339933;">&amp;</span>quot<span style="color: #339933;">;</span>.<span style="color: #660066;">jpg</span><span style="color: #339933;">&amp;</span>quot<span style="color: #339933;">;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; mock<span style="color: #009900;">&#40;</span> fr <span style="color: #009900;">&#41;</span>.<span style="color: #660066;">getter</span><span style="color: #009900;">&#40;</span> <span style="color: #339933;">&amp;</span>quot<span style="color: #339933;">;</span>size<span style="color: #339933;">&amp;</span>quot<span style="color: #339933;">;</span> <span style="color: #009900;">&#41;</span>.<span style="color: #660066;">returns</span><span style="color: #009900;">&#40;</span> 10000 <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; mock<span style="color: #009900;">&#40;</span> fr <span style="color: #009900;">&#41;</span>.<span style="color: #660066;">getter</span><span style="color: #009900;">&#40;</span> <span style="color: #339933;">&amp;</span>quot<span style="color: #339933;">;</span>name<span style="color: #339933;">&amp;</span>quot<span style="color: #339933;">;</span> <span style="color: #009900;">&#41;</span>.<span style="color: #660066;">returns</span><span style="color: #009900;">&#40;</span> <span style="color: #339933;">&amp;</span>quot<span style="color: #339933;">;</span>fr<span style="color: #339933;">&amp;</span>quot<span style="color: #339933;">;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; mock<span style="color: #009900;">&#40;</span> fr <span style="color: #009900;">&#41;</span>.<span style="color: #660066;">method</span><span style="color: #009900;">&#40;</span> <span style="color: #339933;">&amp;</span>quot<span style="color: #339933;">;</span>toString<span style="color: #339933;">&amp;</span>quot<span style="color: #339933;">;</span> <span style="color: #009900;">&#41;</span>.<span style="color: #660066;">returns</span><span style="color: #009900;">&#40;</span> <span style="color: #339933;">&amp;</span>quot<span style="color: #339933;">;</span>FileReference<span style="color: #339933;">&amp;</span>quot<span style="color: #339933;">;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; mock<span style="color: #009900;">&#40;</span> fr <span style="color: #009900;">&#41;</span>.<span style="color: #660066;">method</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>quot<span style="color: #339933;">;</span>load<span style="color: #339933;">&amp;</span>quot<span style="color: #339933;">;</span><span style="color: #009900;">&#41;</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.<span style="color: #660066;">dispatches</span><span style="color: #009900;">&#40;</span> <span style="color: #003366; font-weight: bold;">new</span> Event<span style="color: #009900;">&#40;</span> Event.<span style="color: #660066;">COMPLETE</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">,</span><span style="color: #003366; font-weight: bold;">false</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.<span style="color: #660066;">dispatches</span><span style="color: #009900;">&#40;</span> <span style="color: #003366; font-weight: bold;">new</span> IOErrorEvent<span style="color: #009900;">&#40;</span> IOErrorEvent.<span style="color: #660066;">IO_ERROR</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">false</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; arr.<span style="color: #660066;">push</span><span style="color: #009900;">&#40;</span> fr <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; mock<span style="color: #009900;">&#40;</span> frl <span style="color: #009900;">&#41;</span>.<span style="color: #660066;">getter</span><span style="color: #009900;">&#40;</span> <span style="color: #339933;">&amp;</span>quot<span style="color: #339933;">;</span>fileList<span style="color: #339933;">&amp;</span>quot<span style="color: #339933;">;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">returns</span><span style="color: #009900;">&#40;</span> arr <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; &nbsp;<br />
&nbsp; &nbsp; mock<span style="color: #009900;">&#40;</span> frl <span style="color: #009900;">&#41;</span>.<span style="color: #660066;">method</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>quot<span style="color: #339933;">;</span>toString<span style="color: #339933;">&amp;</span>quot<span style="color: #339933;">;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">returns</span><span style="color: #009900;">&#40;</span> <span style="color: #339933;">&amp;</span>quot<span style="color: #339933;">;</span>FileReferenceList<span style="color: #339933;">&amp;</span>quot<span style="color: #339933;">;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; mock<span style="color: #009900;">&#40;</span> frl <span style="color: #009900;">&#41;</span>.<span style="color: #660066;">method</span><span style="color: #009900;">&#40;</span> <span style="color: #339933;">&amp;</span>quot<span style="color: #339933;">;</span>browse<span style="color: #339933;">&amp;</span>quot<span style="color: #339933;">;</span> <span style="color: #009900;">&#41;</span>.<span style="color: #660066;">args</span><span style="color: #009900;">&#40;</span> Array <span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #660066;">dispatches</span><span style="color: #009900;">&#40;</span> <span style="color: #003366; font-weight: bold;">new</span> Event<span style="color: #009900;">&#40;</span> Event.<span style="color: #660066;">SELECT</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">false</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; &nbsp;<br />
&nbsp; &nbsp; _uploader.<span style="color: #660066;">fileReferenceList</span> <span style="color: #339933;">=</span> frl<span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>事件处理cancelHandler方法如下：</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;height:300px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #006600; font-style: italic;">/**<br />
&nbsp; * 上传过程中中断处理<br />
&nbsp; * &nbsp;<br />
&nbsp; * @param e<br />
&nbsp; * @param pd<br />
&nbsp; * <br />
&nbsp; */</span> &nbsp; &nbsp; &nbsp; &nbsp;<br />
<span style="color: #003366; font-weight: bold;">private</span> <span style="color: #003366; font-weight: bold;">function</span> cancelHandler<span style="color: #009900;">&#40;</span>e<span style="color: #339933;">:</span>UploaderEvent<span style="color: #339933;">,</span> pd<span style="color: #339933;">:</span>Object<span style="color: #009900;">&#41;</span><span style="color: #339933;">:</span><span style="color: #000066; font-weight: bold;">void</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> sHandler<span style="color: #339933;">:</span><span style="color: #003366; font-weight: bold;">Function</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">switch</span><span style="color: #009900;">&#40;</span> pd.<span style="color: #660066;">type</span> <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #000066; font-weight: bold;">case</span> <span style="color: #3366CC;">&quot;m&quot;</span><span style="color: #339933;">:</span> &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sHandler <span style="color: #339933;">=</span> Async.<span style="color: #660066;">asyncHandler</span><span style="color: #009900;">&#40;</span> <span style="color: #000066; font-weight: bold;">this</span><span style="color: #339933;">,</span> cancelHandler<span style="color: #339933;">,</span> <span style="color: #CC0000;">5000</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#123;</span>num<span style="color: #339933;">:</span><span style="color: #CC0000;">4</span><span style="color: #339933;">,</span> type<span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;a&quot;</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> timeoutHandler <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _uploader.<span style="color: #660066;">addEventListener</span><span style="color: #009900;">&#40;</span> UploaderEvent.<span style="color: #660066;">EVENT_FILE_COMPLETE</span><span style="color: #339933;">,</span> sHandler <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _uploader.<span style="color: #660066;">upload</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #000066; font-weight: bold;">break</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #000066; font-weight: bold;">case</span> <span style="color: #3366CC;">&quot;a&quot;</span><span style="color: #339933;">:</span> &nbsp; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span> <span style="color: #339933;">++</span>_count <span style="color: #339933;">==</span> 2 <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _uploader.<span style="color: #660066;">cancel</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Assert.<span style="color: #660066;">assertEquals</span><span style="color: #009900;">&#40;</span> <span style="color: #3366CC;">&quot;cancel失效：&quot;</span><span style="color: #339933;">,</span> 2<span style="color: #339933;">,</span> _uploader.<span style="color: #660066;">uploadedIDAll</span>.<span style="color: #660066;">length</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
<span style="color: #009900;">&#125;</span></div></div>
<p>如上所示：</p>
<p>调用_uploader.browse()，</p>
<p>派发Event.SELECT事件</p>
<p>Uploader内部把文件内容加载到内存，派发UploaderEvent.EVENT_FILE_ALL_MEMEORY事件</p>
<p>在CancelHandler中处理UploaderEvent.EVENT_FILE_ALL_MEMEORY事件</p>
<p>假如pd的属性type为m，进行上传</p>
<p>通过_count变量判断上传了两次，调用_uploader.cancle()方法</p>
<p>进行Assert，判断上传成功的数组列表的长度是否为2</p>
<p>失败的话，输出”cancel失效： ”</p>
<h2>参考资料</h2>
<ul>
<li><a href="http://docs.flexunit.org/"><font size="3">http://docs.flexunit.org/</font></a><font size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; flexunit官方教程 </font></li>
<li><a href="http://tutorials.digitalprimates.net/index.htm"><font size="3">http://tutorials.digitalprimates.net/index.htm</font></a><font size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; flexunit4.1完整教程 </font></li>
<li><a title="https://github.com/flexunit/flexunit" href="https://github.com/flexunit/flexunit">https://github.com/flexunit/flexunit</a><font size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; flexunit4源代码</font> </li>
<li><font size="3"><a href="http://mockolate.org">http://mockolate.org</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mockolate官方教程</font> </li>
<li><a title="http://hudson-ci.org/" href="http://hudson-ci.org/">http://hudson-ci.org/</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hudson官网 </li>
<li><a href="http://www.unitedmindset.com/jonbcampos/2010/02/02/run-flex-unit-tests-from-ant/"><font size="3">http://www.unitedmindset.com/jonbcampos/2010/02/02/run-flex-unit-tests-from-ant/</font></a><font size="3"> </font></li>
<li><a href="http://flexunit.digitalprimates.net:8080/view/All/"><font size="3">http://flexunit.digitalprimates.net:8080/view/All/</font></a><font size="3"> </font></li>
<li><a href="http://blog.csdn.net/lixuekun820/article/details/5881647"><font size="3">http://blog.csdn.net/lixuekun820/article/details/5881647</font></a><font size="3"> </font></li>
<li><a href="http://www.flexonjava.net/2008/12/flex-3-unable-to-resolve-resource.html"><font size="3">http://www.flexonjava.net/2008/12/flex-3-unable-to-resolve-resource.html</font></a><font size="3"> </font></li>
<li><a href="http://macleo.iteye.com/blog/870004"><font size="3">http://macleo.iteye.com/blog/870004</font></a><font size="3"> </font></li>
<li><a href="http://stackoverflow.com/questions/3714957/address-already-in-use-jvm-bind"><font size="3">http://stackoverflow.com/questions/3714957/address-already-in-use-jvm-bind</font></a><font size="3"> </font></li>
<li><a href="http://forums.adobe.com/community/opensource/flexunit?view=all"><font size="3">http://forums.adobe.com/community/opensource/flexunit?view=all</font></a><font size="3"> </font></li>
<li><a href="https://gist.github.com/1094408"><font size="3">https://gist.github.com/1094408</font></a><font size="3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></li>
<li><font size="3">更多资料，请baidu一下-_-</font> </li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.baiduux.com/blog/2012/02/06/flash-ci-and-testing/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>虚拟机与JavaScript引擎的实现与优化</title>
		<link>http://www.baiduux.com/blog/2011/12/22/virtual-machine-and-javascript-engine/</link>
		<comments>http://www.baiduux.com/blog/2011/12/22/virtual-machine-and-javascript-engine/#comments</comments>
		<pubDate>Thu, 22 Dec 2011 03:47:11 +0000</pubDate>
		<dc:creator>nwind</dc:creator>
				<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://www.baiduux.com/blog/?p=1192</guid>
		<description><![CDATA[分享一个内部技术交流的ppt，介绍了虚拟机中的实现方法和现代JavaScript引擎中的优化技巧，对JavaScript实现感兴趣的同学可以参考。
作者水平有限，不能保证内容完全准确，有不正确的地方请大家帮忙指出  
 Virtual machine and javascript engine 
 View more presentations from nwind 

]]></description>
			<content:encoded><![CDATA[<p>分享一个内部技术交流的ppt，介绍了虚拟机中的实现方法和现代JavaScript引擎中的优化技巧，对JavaScript实现感兴趣的同学可以参考。</p>
<p>作者水平有限，不能保证内容完全准确，有不正确的地方请大家帮忙指出 <img src='http://www.baiduux.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<div style="width:620px" id="__ss_10652908"> <strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/nwind/virtual-machine-and-javascript-engine" title="Virtual machine and javascript engine" target="_blank">Virtual machine and javascript engine</a></strong> <iframe src="http://www.slideshare.net/slideshow/embed_code/10652908" width="620" height="399" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe>
<div style="padding:5px 0 12px"> View more <a href="http://www.slideshare.net/" target="_blank">presentations</a> from <a href="http://www.slideshare.net/nwind" target="_blank">nwind</a> </div>
</p></div>
]]></content:encoded>
			<wfw:commentRss>http://www.baiduux.com/blog/2011/12/22/virtual-machine-and-javascript-engine/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>初识前端模板</title>
		<link>http://www.baiduux.com/blog/2011/07/11/introduction-of-template/</link>
		<comments>http://www.baiduux.com/blog/2011/07/11/introduction-of-template/#comments</comments>
		<pubDate>Mon, 11 Jul 2011 09:26:35 +0000</pubDate>
		<dc:creator>yaya</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[前端技术]]></category>

		<guid isPermaLink="false">http://www.baiduux.com/blog/?p=1109</guid>
		<description><![CDATA[总述
 
“模板”这个词，可能很多人第一印象是后端的技术（Smarty，Velocity等），但本文要讲的却不是后端的概念，而是前端开发中所使用到的一种技术，也就是“前端模板”技术。
模板的工作原理可以简单地分成两个步骤：模板解析（翻译）和数据渲染。这两个步骤可分别部署在前端或后端来执行。如果都放在后端执行，则是像Smarty这样的后端模板，而如果都放在前端来执行，则是我们要探讨的前端模板。
问题
 
随着前端交互的复杂性不变提升，无刷新页面数据传输与渲染越发地频繁化，我们发现传统的前端开发方式在ajax数据渲染等方面存在着一个主要问题：繁琐的数据渲染。当前端从后台通过ajax等方式或许到数据后，如果要将这个数据渲染到指定的dom元素中，则需要进行各种字符串拼接工作或者一系列创建元素的工作，还不论细节的问题（单引号双引号问题等），不管是哪一种形式，都是繁琐且费时的。同时，在可读性与维护性上也存在问题。试想，各种循环操作的字符串拼接，元素创建插入，在需要修改时，都需要重新花费不少时间与精力。那有什么方法可以解决这个问题呢?
原理 
 
当我们在JSP中写&#60;ul&#62;&#60;li&#62;&#60;%= name %&#62;&#60;/li&#62;&#60;/ul&#62;的时候，其实就是在应用模板，在后台这句话会被转换成out.print(&#8220;&#60;ul&#62;&#60;li&#62;&#8221;+name+&#8221;&#60;/li&#62;&#60;/ul&#62;&#8221;)。模板的数据渲染就是把模板中的占位符（这里是”name”），替换成传入的值（比如替换成”yaya”）。而在前端开发中，这种方式依然具有很高实用价值。前端模板的核心是前端模板引擎，引擎将前端的模板语言转换成浏览器可以解析的html语言。当转换成功后，便可以很方便地将这段html代码放到我们希望的地方去。



比如我们可以写一段循环的li标签的前端模板语言。通过前端模板引擎转换后成本一连串得li标签的html语言。这时候就可以直接采用innerHTML方法把html代码插入到ul对象中，那么就完成了生成ul列表的功能。

初识 
 
前端的模板核心是模板解析引擎，而解析引擎的主要作用是将模板语言转换成html/xml格式。不同的前端模板有着不同的模板语言，解析引擎因此也各不相同。让我们先来认识几款前端模板，了解下它们各自的模板语言。
Yaya Template是一款轻量级的模板引擎，采用原生javascript语法，具有易学易用等特点。我们来看一段用Yaya Template渲染列表数据的实例：
模板语言（通用过for循环，输出“这是第n列”的li列表）





for(var i=0;i&#60;list.length;i++){
 {$ &#60;li&#62;这是第 {% i %} 列：{% list[i] %}&#60;/li&#62; $}
}





有了模板语言后，我们只需要将数据“打入”模板语言中的”list”，就可以生成我们想要的html/xml格式了。如上例，我们只需要得到这个模板语言进行翻译，并调用对应的render方法，





var list = [“红桃”,”方块”,”梅花”,”黑桃”];
var html = YayaTemplate(templateText).render({list:list});





这个html则是模板引擎转换成的html/xml语言，在上例中，则为：





&#60;li&#62;这是第0列：红桃&#60;/li&#62;
&#60;li&#62;这是第1列：方块&#60;/li&#62;
&#60;li&#62;这是第2列：梅花&#60;/li&#62;
&#60;li&#62;这是第3列：黑桃&#60;/li&#62;





从这个例子中，我们可以发现，{$&#8230;$}表示输出的html/xml片段，{%&#8230;%}表示输出javascript变量。得到的html，我们可以用直接作为dom的innerHTML或者其他用处。
这便是前端模板，它使得我们不必去处理字符串拼接等问题，用最直观的方式来渲染数据。我们再来看另外一款前端模板EasyTemplate。还是之前的例子，用EasyTemplate模板写法如下：





&#60;#list data as list&#62;
 &#60;li&#62;这里是第${list_index} 列：${list}&#60;/li&#62;
&#60;/#list&#62;





同样，需要将实际数据替换模板变量，这里采用：





var list = [“红桃”,”方块”,”梅花”,”黑桃”];
var html = easyTemplate.render(templateText,list);   //templateText指模板语言





像EasyTemplate这样的前端模板，是属于自定义模板语言的一种前端模板。我们可以从上例看出，””就是EasyTemplate自定义的循环条件。像这样EasyTemplate 模板一样采用自定义标签的前端模板还有 lite Template:





&#60;c:for var=”item” list=”${list}”&#62;
 &#60;li&#62;这里是第${for.index}列：${item}&#60;/li&#62;
&#60;/c:for&#62;





渲染时采用：





var list = [“红桃”,”方块”,”梅花”,”黑桃”];
 var   html = [...]]]></description>
			<content:encoded><![CDATA[<h2 style="text-align: center"><strong>总述</strong></h2>
<p><strong> </strong></p>
<p>“模板”这个词，可能很多人第一印象是后端的技术（Smarty，Velocity等），但本文要讲的却不是后端的概念，而是前端开发中所使用到的一种技术，也就是“前端模板”技术。</p>
<p>模板的工作原理可以简单地分成两个步骤：模板解析（翻译）和数据渲染。这两个步骤可分别部署在前端或后端来执行。如果都放在后端执行，则是像Smarty这样的后端模板，而如果都放在前端来执行，则是我们要探讨的前端模板。</p>
<h2 style="text-align: center"><strong>问题</strong></h2>
<p><strong> </strong></p>
<p>随着前端交互的复杂性不变提升，无刷新页面数据传输与渲染越发地频繁化，我们发现传统的前端开发方式在ajax数据渲染等方面存在着一个主要问题：繁琐的数据渲染。当前端从后台通过ajax等方式或许到数据后，如果要将这个数据渲染到指定的dom元素中，则需要进行各种字符串拼接工作或者一系列创建元素的工作，还不论细节的问题（单引号双引号问题等），不管是哪一种形式，都是繁琐且费时的。同时，在可读性与维护性上也存在问题。试想，各种循环操作的字符串拼接，元素创建插入，在需要修改时，都需要重新花费不少时间与精力。那有什么方法可以解决这个问题呢?</p>
<h2 style="text-align: center"><strong>原理</strong><strong> </strong></h2>
<p><strong> </strong></p>
<p>当我们在<span style="font-family: Calibri">JSP</span>中写<span style="font-family: Calibri">&lt;ul&gt;&lt;li&gt;&lt;%= name %&gt;&lt;/li&gt;&lt;/ul&gt;</span>的时候，其实就是在应用模板，在后台这句话会被转换成<span style="font-family: Calibri">out.print(&#8220;&lt;ul&gt;&lt;li&gt;&#8221;+name+&#8221;&lt;/li&gt;&lt;/ul&gt;&#8221;)</span>。模板的数据渲染就是把模板中的占位符（这里是”name”），替换成传入的值（比如替换成”yaya”）。而在前端开发中，这种方式依然具有很高实用价值。前端模板的核心是前端模板引擎，引擎将前端的模板语言转换成浏览器可以解析的html语言。当转换成功后，便可以很方便地将这段html代码放到我们希望的地方去。</p>
<p><br class="spacer_" /></p>
<p style="text-align: center"><img class="aligncenter" src="http://imgsrc.baidu.com/forum/mpic/item/2f712ccf73842a58b700c832.jpg" alt="" width="459" height="63" /></p>
<p><br class="spacer_" /></p>
<p>比如我们可以写一段循环的li标签的前端模板语言。通过前端模板引擎转换后成本一连串得li标签的html语言。这时候就可以直接采用innerHTML方法把html代码插入到ul对象中，那么就完成了生成ul列表的功能。</p>
<p><span id="more-1109"></span></p>
<h2 style="text-align: center"><strong>初识</strong><strong> </strong></h2>
<p><strong> </strong></p>
<p>前端的模板核心是模板解析引擎，而解析引擎的主要作用是将模板语言转换成html/xml格式。不同的前端模板有着不同的模板语言，解析引擎因此也各不相同。让我们先来认识几款前端模板，了解下它们各自的模板语言。</p>
<p><strong><em>Yaya Template</em></strong>是一款轻量级的模板引擎，采用原生javascript语法，具有易学易用等特点。我们来看一段用<strong><em>Yaya Template</em></strong>渲染列表数据的实例：</p>
<p>模板语言（通用过for循环，输出“这是第n列”的li列表）</p>
<p><br class="spacer_" /></p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="568" valign="top">
<p><strong><span style="color: #000000">for(var i=0;i&lt;list.length;i++){</span></strong></p>
<p><span style="color: #000000"><strong> {$ &lt;li&gt;</strong><strong>这是第</strong><strong> {% i %} </strong><strong>列：</strong><strong>{% list[i] %}&lt;/li&gt; $}</strong></span></p>
<p><strong><span style="color: #000000">}</span></strong></p>
</td>
</tr>
</tbody>
</table>
<p><br class="spacer_" /></p>
<p>有了模板语言后，我们只需要将数据“打入”模板语言中的”list”，就可以生成我们想要的html/xml格式了。如上例，我们只需要得到这个模板语言进行翻译，并调用对应的render方法，</p>
<p><br class="spacer_" /></p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="568" valign="top">
<p><strong>var list = [“</strong><strong>红桃</strong><strong>”,”</strong><strong>方块</strong><strong>”,”</strong><strong>梅花</strong><strong>”,”</strong><strong>黑桃</strong><strong>”];</strong></p>
<p><strong>var html = YayaTemplate(templateText).render({list:list});</strong></p>
</td>
</tr>
</tbody>
</table>
<p><br class="spacer_" /></p>
<p>这个html则是模板引擎转换成的html/xml语言，在上例中，则为：</p>
<p><br class="spacer_" /></p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="568" valign="top">
<p><strong>&lt;li&gt;</strong><strong>这是第</strong><strong>0</strong><strong>列：红桃</strong><strong>&lt;/li&gt;</strong></p>
<p><strong>&lt;li&gt;</strong><strong>这是第</strong><strong>1</strong><strong>列：方块</strong><strong>&lt;/li&gt;</strong></p>
<p><strong>&lt;li&gt;</strong><strong>这是第</strong><strong>2</strong><strong>列：梅花</strong><strong>&lt;/li&gt;</strong></p>
<p><strong>&lt;li&gt;</strong><strong>这是第</strong><strong>3</strong><strong>列：黑桃</strong><strong>&lt;/li&gt;</strong></p>
</td>
</tr>
</tbody>
</table>
<p><br class="spacer_" /></p>
<p>从这个例子中，我们可以发现，{$&#8230;$}表示输出的html/xml片段，{%&#8230;%}表示输出javascript变量。得到的html，我们可以用直接作为dom的innerHTML或者其他用处。</p>
<p>这便是前端模板，它使得我们不必去处理字符串拼接等问题，用最直观的方式来渲染数据。我们再来看另外一款前端模板<strong><em>EasyTemplate</em></strong>。还是之前的例子，用<strong><em>EasyTemplate</em></strong>模板写法如下：</p>
<p><br class="spacer_" /></p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="568" valign="top">
<p><strong>&lt;#list data as list&gt;</strong></p>
<p><strong> &lt;li&gt;</strong><strong>这里是第</strong><strong>${list_index} </strong><strong>列：</strong><strong>${list}&lt;/li&gt;</strong></p>
<p><strong>&lt;/#list&gt;</strong></p>
</td>
</tr>
</tbody>
</table>
<p><br class="spacer_" /></p>
<p>同样，需要将实际数据替换模板变量，这里采用：</p>
<p><br class="spacer_" /></p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="568" valign="top">
<p><strong>var list = [“</strong><strong>红桃</strong><strong>”,”</strong><strong>方块</strong><strong>”,”</strong><strong>梅花</strong><strong>”,”</strong><strong>黑桃</strong><strong>”];</strong></p>
<p><strong>var html = easyTemplate.render(templateText,list);   //templateText</strong><strong>指模板语言</strong></p>
</td>
</tr>
</tbody>
</table>
<p><br class="spacer_" /></p>
<p>像<strong><em>EasyTemplate</em></strong>这样的前端模板，是属于自定义模板语言的一种前端模板。我们可以从上例看出，””就是<strong><em>EasyTemplate</em></strong>自定义的循环条件。像这样<strong><em>EasyTemplate </em></strong>模板一样采用自定义标签的前端模板还有<strong><em> lite Template</em></strong>:</p>
<p><br class="spacer_" /></p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="568" valign="top">
<p><strong>&lt;c:for var=”item” list=”${list}”&gt;</strong></p>
<p><strong> &lt;li&gt;</strong><strong>这里是第</strong><strong>${for.index}</strong><strong>列：</strong><strong>${item}&lt;/li&gt;</strong></p>
<p><strong>&lt;/c:for&gt;</strong></p>
</td>
</tr>
</tbody>
</table>
<p><br class="spacer_" /></p>
<p>渲染时采用：</p>
<p><br class="spacer_" /></p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="568" valign="top">
<p><strong>var list = [“</strong><strong>红桃</strong><strong>”,”</strong><strong>方块</strong><strong>”,”</strong><strong>梅花</strong><strong>”,”</strong><strong>黑桃</strong><strong>”];</strong></p>
<p><strong> var   html = liteFunction(templateText,’list’)(list);</strong></p>
</td>
</tr>
</tbody>
</table>
<p><br class="spacer_" /></p>
<p>好了，我们再来看看<strong><em>jquery</em></strong>作者<strong><em>John Resig</em></strong>所写的一个前端模板<strong><em>jquery template</em></strong>。说真的，它如同<strong><em>jquery</em></strong>一样，短小精悍。还是老例子：</p>
<p><br class="spacer_" /></p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="568" valign="top">
<p><strong> &lt;% for(var i=0;i&lt;list.length;i++){ %&gt;</strong></p>
<p><strong>&lt;li&gt;</strong><strong>这是第</strong><strong> &lt;%=i%&gt; </strong><strong>列：</strong><strong>&lt;%= list[i] %&gt;&lt;/li&gt;</strong></p>
<p><strong> &lt;% } %&gt;</strong></p>
</td>
</tr>
</tbody>
</table>
<p><br class="spacer_" /></p>
<p>渲染采用：</p>
<p><br class="spacer_" /></p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="568" valign="top">
<p><strong>var list = [“</strong><strong>红桃</strong><strong>”,”</strong><strong>方块</strong><strong>”,”</strong><strong>梅花</strong><strong>”,”</strong><strong>黑桃</strong><strong>”];</strong></p>
<p><strong>var html = tmpl(&#8220;templateid&#8221;, list);</strong></p>
</td>
</tr>
</tbody>
</table>
<p><br class="spacer_" /></p>
<p>我们可以看出，<strong><em>Yaya Template</em></strong>与<strong><em>jquery template</em></strong>在模板语言的写法上正好相反。前者将输出html语言做特殊标记{$&#8230;$}，而后者对javascript语言做特殊标记。这两种模板已经使得学习成本很低了，而接下来介绍的<strong><em>ace template</em></strong>的写法将更加简单易懂。</p>
<p><br class="spacer_" /></p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="568" valign="top">
<p><strong>for(var i=0;i&lt;list.length;i++){</strong></p>
<p><strong>&lt;li&gt;</strong><strong>这是第</strong><strong> #{ i } </strong><strong>列：</strong><strong>#{ list[i] }&lt;/li&gt;</strong></p>
<p><strong> }</strong></p>
</td>
</tr>
</tbody>
</table>
<p><br class="spacer_" /></p>
<p>渲染采用：</p>
<p><br class="spacer_" /></p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="568" valign="top">
<p><strong>var list = [“</strong><strong>红桃</strong><strong>”,”</strong><strong>方块</strong><strong>”,”</strong><strong>梅花</strong><strong>”,”</strong><strong>黑桃</strong><strong>”];</strong></p>
<p><strong>var html = AceTemplate.format(&#8220;templateid&#8221;, {list:list});</strong></p>
</td>
</tr>
</tbody>
</table>
<p><br class="spacer_" /></p>
<p><strong><em>ace template</em></strong>采用了html与js语言直接混搭的风格，在两者间可以直接的书写，不用添加任何的标志用以区分不同的语言。而在html语言里面，使用js变量则采用#{}的方式输出。<strong><em>ace template</em></strong>之所以可以兼容html与js混合写法，是通过按行解析来实现的。所以，如果代码能够保证html语言与js按行划分，这样的用法其实是很方便的。并且<strong><em>ace template</em></strong>值得说明的一点是支持自动编码防止xss漏洞，通过#{}渲染出来的javascript变量，已经经过了编码处理，这一点是很方便的。而对于不需要这个功能，需要原文输出的时候，<strong><em>ace template</em></strong>也提供了!#{}方法来满足这种需求。</p>
<p>通过上面对五个前端模板的简单介绍，我们可以了解到不同前端模板的各种形态，这包括写法与用法等直观印象。但我们知道，前端模板的核心是代码的转换，这肯定是需要转换时间的，那就以上五个不同的前端模板，性能上会有怎样不同的表现呢。</p>
<p><strong> </strong></p>
<p><strong> </strong></p>
<h2 style="text-align: center"><strong>性能</strong><strong> </strong></h2>
<p><strong> </strong></p>
<p>前端模板语言到html/xml语言，是通过模板引擎进行翻译的。而模板引擎的翻译性能在某种程度上决定了前端模板解决方案的可行性的高低。上诉五种前端模板，各自的性能会是怎么样的，我们对它们进行测试。分别对<strong><em>Yaya Template</em></strong>、<strong><em>EasyTemplate</em></strong>、<strong><em>jquery template</em></strong>、<strong><em> ace template</em></strong>、<strong><em>lite template</em></strong>部署前端模板做同样的操作，比较模板引擎翻译时间代价。</p>
<p>各自的模板代码如下：</p>
<p><strong><em>Yaya Templat</em></strong></p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="568" valign="top">
<p><strong> for (var i=0;i&lt;list.length;i++){</strong></p>
<p><strong> if (i&lt;100){</strong></p>
<p><strong> {$&lt;li&gt;</strong><strong>小于</strong><strong>100 </strong><strong>这里是第</strong><strong>{%i%} </strong><strong>列：</strong><strong>{%list[i]%}&lt;/li&gt;$}</strong></p>
<p><strong> }</strong></p>
<p><strong> else{</strong></p>
<p><strong> {$&lt;li&gt;</strong><strong>不小于</strong><strong>100 </strong><strong>这里是第</strong><strong>{%i%} </strong><strong>列：</strong><strong>{%list[i]%}&lt;/li&gt;$}</strong></p>
<p><strong> }</strong></p>
<p><strong> }</strong></p>
</td>
</tr>
</tbody>
</table>
<p><br class="spacer_" /></p>
<p><strong><em>EasyTemplate</em></strong></p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="568" valign="top">
<p><strong> &lt;#list data as list&gt;</strong></p>
<p><strong> &lt;#if (list_index &lt;100)&gt;</strong></p>
<p><strong> &lt;li&gt;</strong><strong>小于</strong><strong>100 </strong><strong>这里是第</strong><strong>${list_index} </strong><strong>列：</strong><strong>${list}&lt;/li&gt;</strong></p>
<p><strong> &lt;#else&gt;</strong></p>
<p><strong> &lt;li&gt;</strong><strong>不小于</strong><strong>100 </strong><strong>这里是第</strong><strong>${list_index} </strong><strong>列：</strong><strong>${list}&lt;/li&gt;</strong></p>
<p><strong> &lt;/#if&gt;</strong></p>
<p><strong> &lt;/#list&gt;</strong></p>
</td>
</tr>
</tbody>
</table>
<p><br class="spacer_" /></p>
<p><strong><em>jquery template</em></strong></p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="568" valign="top">
<p><strong> &lt;% for (var i=0;i&lt;list.length;i++){ %&gt;</strong></p>
<p><strong> &lt;% if (i&lt;100) { %&gt;</strong></p>
<p><strong> &lt;li&gt;</strong><strong>小于</strong><strong>100 </strong><strong>这里是第</strong><strong>&lt;%=i%&gt;</strong><strong>列：</strong><strong>&lt;%=list[i]%&gt;&lt;/li&gt;</strong></p>
<p><strong> &lt;%  } else{  %&gt;</strong></p>
<p><strong> &lt;li&gt;</strong><strong>不小于</strong><strong>100 </strong><strong>这里是第</strong><strong>&lt;%=i%&gt;</strong><strong>列：</strong><strong>&lt;%=list[i]%&gt;&lt;/li&gt;</strong></p>
<p><strong> &lt;% } %&gt;</strong></p>
<p><strong> &lt;% } %&gt;</strong></p>
</td>
</tr>
</tbody>
</table>
<p><br class="spacer_" /></p>
<p><strong><em>ace template</em></strong></p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="568" valign="top">
<p><strong> for (var i=0;i&lt;list.length;i++){</strong></p>
<p><strong> if (i&lt;100){</strong></p>
<p><strong> &lt;li&gt;</strong><strong>小于</strong><strong>100 </strong><strong>这里是第</strong><strong>#{i} </strong><strong>列：</strong><strong>#{list[i]}&lt;/li&gt;</strong></p>
<p><strong> }</strong></p>
<p><strong> else{</strong></p>
<p><strong> &lt;li&gt;</strong><strong>不小于</strong><strong>100 </strong><strong>这里是第</strong><strong>#{i} </strong><strong>列：</strong><strong>#{list[i]}&lt;/li&gt;</strong></p>
<p><strong> }</strong></p>
<p><strong> }</strong></p>
</td>
</tr>
</tbody>
</table>
<p><br class="spacer_" /></p>
<p><strong><em>lite template</em></strong></p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="568" valign="top">
<p><strong> &lt;c:for var=&#8221;item&#8221; list=&#8221;${list}&#8221;&gt;</strong></p>
<p><strong> &lt;c:if test=&#8221;${for.index&amp;lt;100}&#8221;&gt;</strong></p>
<p><strong> &lt;li&gt;</strong><strong>小</strong><strong> </strong><strong>于</strong><strong>100 </strong><strong>这里是第</strong><strong> $!{for.index} </strong><strong>列：</strong><strong>$!{item}&lt;/li&gt;</strong></p>
<p><strong> &lt;/c:if&gt;</strong></p>
<p><strong> &lt;c:else&gt;</strong></p>
<p><strong> &lt;li&gt;</strong><strong>不小于</strong><strong>100 </strong><strong>这里是第</strong><strong>$!{for.index} </strong><strong>列：</strong><strong>$!{item}&lt;/li&gt;</strong></p>
<p><strong> &lt;/c:else&gt;</strong></p>
<p><strong> &lt;/c:for&gt;</strong></p>
</td>
</tr>
</tbody>
</table>
<p><br class="spacer_" /></p>
<p>然后我们改变list数组里面的元素个数，对各个模板翻译执行的时间进行记录。结果如下(xp+ie6/ie8/firefox/chrome运行环境)：</p>
<p>模板翻译时间对比表(第一次翻译并渲染数据 时间单位:毫秒)</p>
<table border="1" cellspacing="0" cellpadding="0" width="660">
<tbody>
<tr>
<td colspan="2" width="100" valign="top">
<p>List长度<strong><em> </em></strong></p>
</td>
<td width="108" valign="top">
<p><strong><em>Yaya Template</em></strong></p>
</td>
<td width="104" valign="top">
<p><strong><em>EasyTemplate</em></strong></p>
</td>
<td width="113" valign="top">
<p><strong><em>jquery template</em></strong></p>
</td>
<td width="113" valign="top">
<p><strong><em>ace template</em></strong></p>
</td>
<td width="109" valign="top">
<p><strong><em>lite template</em></strong></p>
</td>
</tr>
<tr>
<td rowspan="4" width="64" valign="top">
<p>1</p>
</td>
<td width="60&quot;" valign="top">
<p>ie6</p>
</td>
<td rowspan="4" width="108" valign="top">
<p>0</p>
<p>0</p>
<p>0</p>
<p>0</p>
</td>
<td rowspan="4" width="104" valign="top">
<p>0</p>
<p>0</p>
<p>0</p>
<p>0</p>
</td>
<td rowspan="4" width="113" valign="top">
<p>0</p>
<p>0</p>
<p>0</p>
<p>0</p>
</td>
<td rowspan="4" width="113" valign="top">
<p>0</p>
<p>0</p>
<p>0</p>
<p>0</p>
</td>
<td rowspan="4" width="109" valign="top">
<p>16</p>
<p>15</p>
<p>12</p>
<p>4</p>
</td>
</tr>
<tr>
<td width="60" valign="top">
<p>ie8</p>
</td>
</tr>
<tr>
<td width="60" valign="top">
<p>firefox</p>
</td>
</tr>
<tr>
<td width="60" valign="top">
<p>chrome</p>
</td>
</tr>
<tr>
<td rowspan="4" width="64" valign="top">
<p>10</p>
</td>
<td width="60" valign="top">
<p>ie6</p>
</td>
<td rowspan="4" width="108" valign="top">
<p>0</p>
<p>0</p>
<p>0</p>
<p>0</p>
</td>
<td rowspan="4" width="104" valign="top">
<p>0</p>
<p>0</p>
<p>0</p>
<p>0</p>
</td>
<td rowspan="4" width="113" valign="top">
<p>0</p>
<p>0</p>
<p>1</p>
<p>0</p>
</td>
<td rowspan="4" width="113" valign="top">
<p>0</p>
<p>0</p>
<p>0</p>
<p>1</p>
</td>
<td rowspan="4" width="109" valign="top">
<p>16</p>
<p>15</p>
<p>11</p>
<p>2</p>
</td>
</tr>
<tr>
<td width="60" valign="top">
<p>ie8</p>
</td>
</tr>
<tr>
<td width="60" valign="top">
<p>firefox</p>
</td>
</tr>
<tr>
<td width="60" valign="top">
<p>chrome</p>
</td>
</tr>
<tr>
<td rowspan="4" width="64" valign="top">
<p>100</p>
</td>
<td width="60" valign="top">
<p>ie6</p>
</td>
<td rowspan="4" width="108" valign="top">
<p>0</p>
<p>0</p>
<p>0</p>
<p>0</p>
</td>
<td rowspan="4" width="104" valign="top">
<p>0</p>
<p>0</p>
<p>0</p>
<p>0</p>
</td>
<td rowspan="4" width="113" valign="top">
<p>0</p>
<p>0</p>
<p>1</p>
<p>1</p>
</td>
<td rowspan="4" width="113" valign="top">
<p>0</p>
<p>0</p>
<p>1</p>
<p>0</p>
</td>
<td rowspan="4" width="109" valign="top">
<p>15</p>
<p>16</p>
<p>10</p>
<p>4</p>
</td>
</tr>
<tr>
<td width="60" valign="top">
<p>ie8</p>
</td>
</tr>
<tr>
<td width="60" valign="top">
<p>firefox</p>
</td>
</tr>
<tr>
<td width="60" valign="top">
<p>chrome</p>
</td>
</tr>
<tr>
<td rowspan="4" width="64" valign="top">
<p>1000</p>
</td>
<td width="60" valign="top">
<p>ie6</p>
</td>
<td rowspan="4" width="108" valign="top">
<p>0</p>
<p>0</p>
<p>1</p>
<p>0</p>
</td>
<td rowspan="4" width="104" valign="top">
<p>16</p>
<p>16</p>
<p>2</p>
<p>3</p>
</td>
<td rowspan="4" width="113" valign="top">
<p>16</p>
<p>0</p>
<p>3</p>
<p>2</p>
</td>
<td rowspan="4" width="113" valign="top">
<p>0</p>
<p>0</p>
<p>2</p>
<p>3</p>
</td>
<td rowspan="4" width="109" valign="top">
<p>15</p>
<p>15</p>
<p>21</p>
<p>7</p>
</td>
</tr>
<tr>
<td width="60" valign="top">
<p>ie8</p>
</td>
</tr>
<tr>
<td width="60" valign="top">
<p>firefox</p>
</td>
</tr>
<tr>
<td width="60" valign="top">
<p>chrome</p>
</td>
</tr>
<tr>
<td rowspan="4" width="64" valign="top">
<p>10000</p>
</td>
<td width="60" valign="top">
<p>ie6</p>
</td>
<td rowspan="4" width="108" valign="top">
<p>63</p>
<p>16</p>
<p>7</p>
<p>4</p>
</td>
<td rowspan="4" width="104" valign="top">
<p>78</p>
<p>47</p>
<p>22</p>
<p>26</p>
</td>
<td rowspan="4" width="113" valign="top">
<p>110</p>
<p>47</p>
<p>27</p>
<p>23</p>
</td>
<td rowspan="4" width="113" valign="top">
<p>62</p>
<p>62</p>
<p>20</p>
<p>22</p>
</td>
<td rowspan="4" width="109" valign="top">
<p>78</p>
<p>31</p>
<p>22</p>
<p>15</p>
</td>
</tr>
<tr>
<td width="60" valign="top">
<p>ie8</p>
</td>
</tr>
<tr>
<td width="60" valign="top">
<p>firefox</p>
</td>
</tr>
<tr>
<td width="60" valign="top">
<p>chrome</p>
</td>
</tr>
<tr>
<td rowspan="4" width="64" valign="top">
<p>100000</p>
</td>
<td width="60" valign="top">
<p>ie6</p>
</td>
<td rowspan="4" width="108" valign="top">
<p>672</p>
<p>250</p>
<p>75</p>
<p>90</p>
</td>
<td rowspan="4" width="104" valign="top">
<p>1719</p>
<p>609</p>
<p>221</p>
<p>304</p>
</td>
<td rowspan="4" width="113" valign="top">
<p>1203</p>
<p>719</p>
<p>267</p>
<p>308</p>
</td>
<td rowspan="4" width="113" valign="top">
<p>750</p>
<p>328</p>
<p>203</p>
<p>288</p>
</td>
<td rowspan="4" width="109" valign="top">
<p>688</p>
<p>250</p>
<p>124</p>
<p>114</p>
</td>
</tr>
<tr>
<td width="85" valign="top">
<p>ie8</p>
</td>
</tr>
<tr>
<td width="85" valign="top">
<p>firefox</p>
</td>
</tr>
<tr>
<td width="85" valign="top">
<p>chrome</p>
</td>
</tr>
</tbody>
</table>
<p><br class="spacer_" /></p>
<p>通过第一次翻译后，如果前端模板可以缓存翻译后的中间代码，或者可以返回构建中间代码的函数，那么再次渲染数据的时候，就不需要再翻译。这样可以极大的缩小渲染数据的时间，提高速度。</p>
<p>综合各种调研数据对比表如下：</p>
<p><br class="spacer_" /></p>
<table border="1" cellspacing="0" cellpadding="0" width="671">
<tbody>
<tr>
<td width="116" valign="top">
<p><br class="spacer_" /></p>
</td>
<td width="101" valign="top">
<p><strong><em>Yaya Template</em></strong></p>
</td>
<td width="103" valign="top">
<p><strong><em>EasyTemplate</em></strong></p>
</td>
<td width="114" valign="top">
<p><strong><em>jquery template</em></strong></p>
</td>
<td width="104" valign="top">
<p><strong><em>ace template</em></strong></p>
</td>
<td width="132" valign="top">
<p><strong><em>lite template</em></strong></p>
</td>
</tr>
<tr>
<td width="116" valign="top">
<p>缓存加速</p>
</td>
<td width="101" valign="top">
<p>有</p>
</td>
<td width="103" valign="top">
<p>无</p>
</td>
<td width="114" valign="top">
<p>有</p>
</td>
<td width="104" valign="top">
<p>有</p>
</td>
<td width="132" valign="top">
<p>有</p>
</td>
</tr>
<tr>
<td width="116" valign="top">
<p>防xss漏洞编码</p>
</td>
<td width="101" valign="top">
<p>无</p>
</td>
<td width="103" valign="top">
<p>无</p>
</td>
<td width="114" valign="top">
<p>无</p>
</td>
<td width="104" valign="top">
<p>有</p>
</td>
<td width="132" valign="top">
<p>有</p>
</td>
</tr>
<tr>
<td width="116" valign="top">
<p>扩展语法</p>
</td>
<td width="101" valign="top">
<p>无</p>
</td>
<td width="103" valign="top">
<p>有</p>
</td>
<td width="114" valign="top">
<p>无</p>
</td>
<td width="104" valign="top">
<p>无</p>
</td>
<td width="132" valign="top">
<p>有</p>
</td>
</tr>
<tr>
<td width="116" valign="top">
<p>错误跟踪</p>
</td>
<td width="101" valign="top">
<p>无</p>
</td>
<td width="103" valign="top">
<p>无</p>
</td>
<td width="114" valign="top">
<p>无</p>
</td>
<td width="104" valign="top">
<p>无</p>
</td>
<td width="132" valign="top">
<p>有</p>
</td>
</tr>
<tr>
<td width="116" valign="top">
<p>代码尺寸（字节）</p>
</td>
<td width="101" valign="top">
<p>483</p>
</td>
<td width="103" valign="top">
<p>1527</p>
</td>
<td width="114" valign="top">
<p>453</p>
</td>
<td width="104" valign="top">
<p>2512</p>
</td>
<td width="132" valign="top">
<p>91511</p>
</td>
</tr>
</tbody>
</table>
<p><strong> </strong></p>
<h2 style="text-align: center"><strong>兼容</strong><strong> </strong></h2>
<p><strong> </strong></p>
<p>前端模板的兼容性也是一个重要的问题。能够实现用户不同的前端模板需求，将前端模板语言正确翻译成html/xml语言，是优秀的前端模板所需要具备的特点。而通过对以上五种前端模板的测试，并没有发现严重的兼容性问题。但在一些细节上，还是发现了一些问题如下表:</p>
<p>兼容性测试对比表</p>
<table border="1" cellspacing="0" cellpadding="0" width="643">
<tbody>
<tr>
<td width="122" valign="top">
<p>测试点</p>
</td>
<td width="105" valign="top">
<p><strong><em>Yaya Template</em></strong></p>
</td>
<td width="97" valign="top">
<p><strong><em>EasyTemplate</em></strong></p>
</td>
<td width="111" valign="top">
<p><strong><em>jquery template</em></strong></p>
</td>
<td width="94" valign="top">
<p><strong><em>ace template</em></strong></p>
</td>
<td width="113" valign="top">
<p><strong><em>lite template</em></strong></p>
</td>
</tr>
<tr>
<td width="122" valign="top">
<p>换行空白</p>
</td>
<td width="105" valign="top">
<p>通过</p>
</td>
<td width="97" valign="top">
<p>空白被省略</p>
</td>
<td width="111" valign="top">
<p>通过</p>
</td>
<td width="94" valign="top">
<p>通过</p>
</td>
<td width="113" valign="top">
<p>通过</p>
</td>
</tr>
<tr>
<td width="122" valign="top">
<p>空白节点</p>
</td>
<td width="105" valign="top">
<p>通过</p>
</td>
<td width="97" valign="top">
<p>通过</p>
</td>
<td width="111" valign="top">
<p>通过</p>
</td>
<td width="94" valign="top">
<p>通过</p>
</td>
<td width="113" valign="top">
<p>通过</p>
</td>
</tr>
<tr>
<td width="122" valign="top">
<p>字符’”/\</p>
</td>
<td width="105" valign="top">
<p>通过</p>
</td>
<td width="97" valign="top">
<p>通过</p>
</td>
<td width="111" valign="top">
<p>\ ‘’未通过</p>
</td>
<td width="94" valign="top">
<p>通过</p>
</td>
<td width="113" valign="top">
<p>通过</p>
</td>
</tr>
<tr>
<td width="122" valign="top">
<p>多层嵌套</p>
</td>
<td width="105" valign="top">
<p>通过</p>
</td>
<td width="97" valign="top">
<p>通过</p>
</td>
<td width="111" valign="top">
<p>通过</p>
</td>
<td width="94" valign="top">
<p>通过</p>
</td>
<td width="113" valign="top">
<p>通过</p>
</td>
</tr>
<tr>
<td width="122" valign="top">
<p>语法检测</p>
</td>
<td width="105" valign="top">
<p>通过</p>
</td>
<td width="97" valign="top">
<p>通过</p>
</td>
<td width="111" valign="top">
<p>不能通过，在if else语句中常用的形态不能处理。</p>
</td>
<td width="94" valign="top">
<p>通过</p>
</td>
<td width="113" valign="top">
<p>通过</p>
</td>
</tr>
</tbody>
</table>
<p><strong> </strong></p>
<p><strong> </strong></p>
<p><strong> </strong></p>
<h2 style="text-align: center"><strong>流程</strong><strong> </strong></h2>
<p><strong> </strong></p>
<p>对于“什么是前端模板，它有什么特性，怎么使用”这样的问题已经通过上面的分析说明给出了答案。但前端模板既然是前端的范畴，就不可能独立存在，而是需要运用到前端开发的流程中的。而采用了前端模版的开发流程与传统的相比又会是怎么样的呢？</p>
<p style="text-align: center"><img class="aligncenter" src="http://imgsrc.baidu.com/forum/mpic/item/57ae0afb1edc597fa9d31132.jpg" alt="" width="546" height="135" /></p>
<p>上图是传统的开发流程。首先将ui设计图转换成html的页面，其中的数据一般先用模拟数据代替。比如，ui设计有个列表，那么可能开发人员会先建立一些模拟的数据填充到节点中，来开发调整页面样式。最后一步，则将需要动态生成（ajax应用等）的地方，将模拟数据的节点变成空白节点，然后在javascript里面拼装这些html节点的字符串，最后再还原到原节点处（比如用innerHTML插入html）。</p>
<p><img class="alignleft" src="http://imgsrc.baidu.com/forum/pic/item/a959ec63f6621abce6113a32.jpg" alt="" width="614" height="170" /></p>
<p>上图是一个实例。当列表中的元素需要ajax动态加载的时候，在传统开发中可能按照先开发模拟数据的html页面，再将这些元素拼接成html字符串，之后再进行一系列处理的功能。</p>
<p>那么，它的问题是什么呢？很明显，“不可逆”是最大的问题。当开发者完成了开发，这时候如果需要修改，那么将是很头疼的事。由于是由字符串拼接出来的html片段，想直接修改这些字符串来改变结构或是修改样式什么的将是一个比重新开发一遍还要具有挑战的工作。所以，开发者往往选择再来一遍吧:html的模拟数据页面，然后再拼接字符串。除了“不可逆”，维护性差以及开发成本高都是采用传统方式开发富客户端应用的弊病。</p>
<p>好吧，我们试着改变这个局面。看看下图，采用前端模板开发的新方式，或许会找到某些答案。</p>
<p><img src="http://imgsrc.baidu.com/forum/pic/item/99a55e08636a8fae3ac76332.jpg" alt="" width="547" height="126" /></p>
<p><br class="spacer_" /></p>
<p>“双向可逆”，是的，采用前端模板的开发方式，在开发好展示的html页面后，直接经过简单的修改即可生成html+template 页面，无需再拼接字符串，无需再反复重写展示模拟数据的html页面，一切都变得很轻松。我们来看看代码便知道原因了（以ace template为例）。</p>
<p><img src="http://imgsrc.baidu.com/forum/pic/item/11ad96c29c66f534b219a833.jpg" alt="" width="629" height="313" /></p>
<p>如果调用模板引擎，当模板执行数据执行后，直接覆盖parentNode里面的内容。而如果想继续调整html结构等，则不调用模板引擎即可。而原有的调试数据，在需要发布的时候可以直接通过代码编译去掉debug start与debug end之间代码即可（这仅仅是前端模块开发的一种实例，实际开发中可以去掉模拟数据，不用编译）。</p>
<h2 style="text-align: center"><strong>展望</strong><strong> </strong></h2>
<p><strong> </strong></p>
<p>前端模板技术其实还有很多的工作要做，比如模板的事件代理，模板的复用性，模板的组件库等等。本文仅对前端模板做了一个大致讲解。相信随着对于前端模板的探索，模板技术会被越来越多得运用的前端开发，特别是富客户端的前端开发中，进一步提高开发效率，为开发人员带来更多的惊喜！</p>
<h2 style="text-align: center">参考资料</h2>
<p><br class="spacer_" /></p>
<p>1.yaya template      <a href="http://uloveit.com.cn/template">http://uloveit.com.cn/template</a></p>
<p>2.easy template       <a href="http://www.easyui.org.cn/easyTemplate.html">http://www.easyui.org.cn/easyTemplate.html</a></p>
<p>3.jquery template    <a href="http://ejohn.org/blog/javascript-micro-templating/">http://ejohn.org/blog/javascript-micro-templating/</a></p>
<p>4.ace template         <a href="http://blog.csdn.net/zswang/article/details/6582563">http://blog.csdn.net/zswang/article/details/6582563</a></p>
<p>5.lite template          <a href="http://code.google.com/p/lite">http://code.google.com/p/lite</a> <a href="http://firekylin.my.baidu.com/">http://firekylin.my.baidu.com</a></p>
<p><br class="spacer_" /></p>
]]></content:encoded>
			<wfw:commentRss>http://www.baiduux.com/blog/2011/07/11/introduction-of-template/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>前端开发中的MCRV模式</title>
		<link>http://www.baiduux.com/blog/2011/07/08/frontend-mcrv-design-pattern/</link>
		<comments>http://www.baiduux.com/blog/2011/07/08/frontend-mcrv-design-pattern/#comments</comments>
		<pubDate>Fri, 08 Jul 2011 09:32:57 +0000</pubDate>
		<dc:creator>izujian</dc:creator>
				<category><![CDATA[HTML/CSS]]></category>
		<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://www.baiduux.com/blog/?p=1150</guid>
		<description><![CDATA[针对前端开发中基于ajax的复杂页面开发所面临的代码规模大，难以组织和维护，代码复用性、扩展性和适应性差等问题，本文尝试以MVC思想为基础，结合Web前端开发中内容-结构-表现-行为相分离的开发标准，提出一种将Web页面代码分为视图（View，页面静态部分，包括内容、结构、表现）、模型(Model，负责数据缓存、数据校验与本地逻辑处理、发起ajax请求)、控制器（Controller，负责用户和系统事件响应、模型和呈现器调度）、呈现器（Renderer，对视图的渲染，控制器与事件的绑定、数据搜集）的页面开发新模式，并基于此模式提出了一个开发框架原型。

摘要 
针对前端开发中基于ajax的复杂页面开发所面临的代码规模大，难以组织和维护，代码复用性、扩展性和适应性差等问题，本文尝试以MVC思想为基础，结合Web前端开发中内容-结构-表现-行为相分离的开发标准，提出一种将Web页面代码分为视图（View，页面静态部分，包括内容、结构、表现）、模型(Model，负责数据缓存、数据校验与本地逻辑处理、发起ajax请求)、控制器（Controller，负责用户和系统事件响应、模型和渲染器调度）、渲染器（Renderer，对视图的渲染，控制器与事件的绑定、数据搜集）的页面开发新模式，并基于此模式提出了一个开发框架原型。

关键字: 
   MCRV设计模式  Javascript  MVC  Web开发标准

 
1.Web前端开发面临的问题 
   早期的Web页开发(Web前端开发)中，Web页面较为简单，大多数Web页面的功能仅限于用HTML和简单样式展示静态信息，或向服务器发送数据，Web页面与用户的交互较少。随着Web的发展，DHTML、CSS、javascript等技术出现，Web页不再仅限于展示静态信息，动态、交互成为Web页的主流功能之一。与此同时，Web页代码规模也变的较大，页面中的HTML、CSS、Javascript等代码往往混杂在一起，如何很好的组织这些代码，使Web客户端程序具有很好的结构，易于阅读和维护，成为Web前端开发人员面临的一个难题。在实践中，业界提出了内容(Content)-结构(Structure)-表现(Presentation)-行为(Behavior)相分离的Web页开发标准。在这种标准中，一个Web页代码可以分为如下四个部分：


    内容：页面实际要传达的真正信息,包含数据、文档或者图片等。
    结构：对内容的划分，使内容更加具有逻辑性，易用性。类似页面的标题、作者、章、节、段落和列表。
    表现：用来描述内容外观，称之为“表现”，主要指CSS样式。
    行为：行为就是对内容的交互及操作效果。行为控制主要通过javascript实现。


内容-结构-表现-行为(CSPB)开发标准对Web页包含的的代码进行了分类，使代码各个部分得到很好的分离，使Web页初步具有了良好的结构。

随后，Web进入了崭新的Web2.0时代，以Gmail为代表的Web2.0应用大量出现，并且取得很大的成功。这类Web页的典型特征是用一个基于ajax技术的无刷新的页面完成大量复杂的功能。此类页面包括Web IM、Web Map、Gmail等应用，统称为one-page Web应用。同时，在企业级Web开发中，一个Web页同时完成多个复杂功能的情况也越来越多。在这些复杂Web页应用中， Javascript代码是此类富客户端应用程序的核心，负责与用户的复杂交互和页面展现。One-page Web页面javascript代码规模往往非常庞大，逻辑复杂，动则千行以上，有时甚至需要一个团队来完成一个页面的开发。如何合理组织大量的javascript代码，使之具有良好的扩展性，能够适应需求的变化，使代码易于维护，是广大Web前端开发人员面临的一大挑战。

纵观Web应用程序开发的历史，Web后端开发(PHP、J2EE、ASP.NET)与Web客户端开发的发展过程有一定的相似性，曾面临类似的问题。最初，Web程序功能简单，代码较少时，所有的控制、逻辑、UI展现代码混杂在一起；随着Web发展，程序规模变大，按原有方式开发出的程序显然不具有良好的结构，不利于大规模开发和后期维护，也不利于Web开发人员工作和角色的进一步细分，代码复用性差，瓶颈开始出现。Web后端程序设计者的解决方法是进行代码分类，将控制代码与展现代码开始分离， 于是Web后端开发从所谓的Model1发展到Model2；同时，传统桌面程序设计中的MVC(模型-视图-控制器)设计模式被引入，负责程序数据与逻辑计算的部分进一步分离出来，形成了Web后端开发中的MVC开发模式。MVC设计模式贯穿了软件工程分而治之的思想，有效解决了Web后端程序设计中的代码组织和复用问题。采用同一设计模式(MVC)也使代码更容易被他人理解，保证代码可靠性；它使Web开发工作可以细分为业务逻辑开发和UI展现开发。因此，MVC也利于团队开发。那么，MVC设计思想是否也能应用在前端开发中解决相关问题呢？既然问题具有许多相似性，笔者沿着相同的解决思路来试图解决前端开发中的代码组织问题。

2.MVC设计模式 
在提出本文提出的MCRV设计模式之前，有必要对其所基于的MVC设计模式进行阐述。

MVC这个概念很早之前就被人提起[1]，它代表一种设计思想。MVC是Model-View-Conroller的缩写，即模型-视图-控制器。这种开发模式将一个应用程序分为三个部分，模型(model)实现商业逻辑，提供数据；视图(view)负责向用户呈现界面和接受用户交互；控制器(controller)则负责响应用户交互请求，对用户请求进行翻译，根据不同的请求调用模型，执行商业逻辑。控制器本质上是一个调度器 (dispatcher)，通过其包含的各个方法(action)来执行具体的商业逻辑。MVC各个部件以最小的耦合性协同工作，从而使程序具有良好的可扩展性和可维护性和复用性。

MVC设计模式最开始被用于桌面程序设计，典型地用于相同的数据需要不同的用户交互界面的设计场景。在经典的MVC设计思想中，控制器负责响应用户事件，根据事件类型和参数调用模型或改变视图。每个模型对应一个或者多个视图，当模型被控制器调用而得到改变时，模型向所有向其注册过的视图发送通知，视图根据从模型的中得到的信息改变外观。这种设计模式可以用图1表示。可以看出经典MVC设计模式中Controller、Model 都可以改变视图。

图1 经典MVC

基于MVC模式的Web开发(后端)一般可以用图2表示。在这种模式下，controller负责解析用户浏览器请求的URL，根据URL自动调用controller中的不同的Action响应用户请求。Action调用model，然后将model返回的数据填充到view中，view被返回给用户浏览器。Web服务端开发中典型的采用MVC模式的框架有CakePHP、Structs、Spring等等。

图2 Server端Web开发中的MVC

相对于早期的经典MVC模式，Web开发中的MVC模式存在一些变化，因为对于一个桌面应用程序而言，可以很方便地将视图注册给模型，当模型数据发生改变时，即时通知视图页面发生改变；而对于Web应用而言，即使将多个页面注册给一个模型，当模型发生变化时，模型无法主动发送消息给Web页面（因为Web应用都是基于请求/响应模式的），只有当用户请求浏览该页面时，控制器才负责调用模型数据来更新Web页面。同时，Web开发中的MVC也比经典MVC具有更小的耦合性，因为Model不再与View发生交互，因此程序的结构更加良好，使Web前端开发和业务逻辑开发相分离变的简单。

对于具有复杂交互逻辑和丰富界面的程序来说，MVC已被实践证明是一种行之有效的设计和开发思想。采用MVC设计模式的系统具有较好的结构，较低的耦合性，代码具有很好的维护性，能够适应复杂的业务逻辑和视图展现变化。它也非常适合团队开发，使开发人员分为不同的角色，专注于自己负责部分的开发。

3.MCRV设计模式 
综上所述，MVC是解决具有复杂交互界面、代码规模大的应用程序面临代码组织、复用问题的有效设计模式。基于此，本文尝试基于MVC设计思想解决前端开发中的类似问题。

然而，在前端页面开发中不能直接套用MVC设计模式。因为，前端开发中的Web页面包含了HTML、CSS、Javascript等多个种类的代码，相对Web后端来说，Web页面整体就是一个负责UI展现、用户本地交互、发送服务请求的大View，与经典MVC及Web后端开发MVC模式中的View皆有不同。因此，需要具体问题具体分析。

首先对Web页面中的HTML、CSS、Javascript等代码进一步分析，明确它们的具体功能分类。根据业界提出的Web开发标准，Web页首先被分为了内容-结构-表现-行为几个部分。内容、结构、表现是页面的静态部分，主要负责UI的展现，用户操作指令（键盘、鼠标）的接受，因此，内容、结构、表现属于视图 (View)的范畴。行为主要就是javascript代码，负责对用户操作指令的响应。在复杂ajax应用中， javascript代码的功能一般包括：响应用户指令，执行数据验证/处理、执行客户端交互逻辑，向服务器发送ajax请求，接受并处理服务器返回的数据，根据数据改变UI（向页面结构填充内容数据、变换样式等）。基于模型-视图-控制器分离的思想，Javascript代码中的数据验证/处理、本地业务逻辑计算、向服务器发请求获取数据的功能，对应模型(Model)的功能；响应(翻译)用户操作指令，根据指令执行业务逻辑处理的功能，属于控制器(Controller)的功能；而接受处理过的数据，根据数据修改页面的内容/结构/样式的功能既不属于控制器的功范畴，也不属于模型的功能范畴，这部分代码因为根据数据对View进行呈现(render)，可以命名为Renderer(渲染器或呈现器)。

根据前述分析，本文提出了MCRV设计模式，如图3所示。阐述如下：


   M(Model)：模型。完成数据验证、数据处理，执行客户端业务逻辑计算，或向服务器发起ajax请求调用服务端逻辑、接受返回的数据，将处理后的数据返回控制器。
   C(Controller)：控制器。控制器响应View上的事件，根据事件调度执行模型的业务逻辑，从业务逻辑获取返回数据，调度相应的渲染器(Render)来完成界面展现。在这个过程中控制器会有数据的传递：控制器调用模型中的逻辑时会传送Renderer搜集的数据(form表单各域的name/value、其他控制参数)，模型执行逻辑后返回作为执行结果的数据给控制器，控制器根据数据来调用渲染器(renderer)来完成界面呈现(rendering)，呈现(rendering)就是修改页面结构、内容和样式的过程。数据传递过程可以用图4表示。
   [...]]]></description>
			<content:encoded><![CDATA[<p>针对前端开发中基于ajax的复杂页面开发所面临的代码规模大，难以组织和维护，代码复用性、扩展性和适应性差等问题，本文尝试以MVC思想为基础，结合Web前端开发中内容-结构-表现-行为相分离的开发标准，提出一种将Web页面代码分为视图（View，页面静态部分，包括内容、结构、表现）、模型(Model，负责数据缓存、数据校验与本地逻辑处理、发起ajax请求)、控制器（Controller，负责用户和系统事件响应、模型和呈现器调度）、呈现器（Renderer，对视图的渲染，控制器与事件的绑定、数据搜集）的页面开发新模式，并基于此模式提出了一个开发框架原型。
</p>
<h2>摘要<a name="摘要"> </a></h2>
<p>针对前端开发中基于ajax的复杂页面开发所面临的代码规模大，难以组织和维护，代码复用性、扩展性和适应性差等问题，本文尝试以MVC思想为基础，结合Web前端开发中内容-结构-表现-行为相分离的开发标准，提出一种将Web页面代码分为视图（View，页面静态部分，包括内容、结构、表现）、模型(Model，负责数据缓存、数据校验与本地逻辑处理、发起ajax请求)、控制器（Controller，负责用户和系统事件响应、模型和渲染器调度）、渲染器（Renderer，对视图的渲染，控制器与事件的绑定、数据搜集）的页面开发新模式，并基于此模式提出了一个开发框架原型。
</p>
<h2>关键字:<a name="关键字"> </a></h2>
<p>   MCRV设计模式  Javascript  MVC  Web开发标准
</p>
<p> <span id="more-1150"></span></p>
<h2>1.Web前端开发面临的问题<a name="1Web前端开发面临的问题"> </a></h2>
<p>   早期的Web页开发(Web前端开发)中，Web页面较为简单，大多数Web页面的功能仅限于用HTML和简单样式展示静态信息，或向服务器发送数据，Web页面与用户的交互较少。随着Web的发展，DHTML、CSS、javascript等技术出现，Web页不再仅限于展示静态信息，动态、交互成为Web页的主流功能之一。与此同时，Web页代码规模也变的较大，页面中的HTML、CSS、Javascript等代码往往混杂在一起，如何很好的组织这些代码，使Web客户端程序具有很好的结构，易于阅读和维护，成为Web前端开发人员面临的一个难题。在实践中，业界提出了内容(Content)-结构(Structure)-表现(Presentation)-行为(Behavior)相分离的Web页开发标准。在这种标准中，一个Web页代码可以分为如下四个部分：
</p>
<div class="code">
<pre>    内容：页面实际要传达的真正信息,包含数据、文档或者图片等。
    结构：对内容的划分，使内容更加具有逻辑性，易用性。类似页面的标题、作者、章、节、段落和列表。
    表现：用来描述内容外观，称之为“表现”，主要指CSS样式。
    行为：行为就是对内容的交互及操作效果。行为控制主要通过javascript实现。
</pre>
</div>
<p>内容-结构-表现-行为(CSPB)开发标准对Web页包含的的代码进行了分类，使代码各个部分得到很好的分离，使Web页初步具有了良好的结构。
</p>
<p>随后，Web进入了崭新的Web2.0时代，以Gmail为代表的Web2.0应用大量出现，并且取得很大的成功。这类Web页的典型特征是用一个基于ajax技术的无刷新的页面完成大量复杂的功能。此类页面包括Web IM、Web Map、Gmail等应用，统称为one-page Web应用。同时，在企业级Web开发中，一个Web页同时完成多个复杂功能的情况也越来越多。在这些复杂Web页应用中， Javascript代码是此类富客户端应用程序的核心，负责与用户的复杂交互和页面展现。One-page Web页面javascript代码规模往往非常庞大，逻辑复杂，动则千行以上，有时甚至需要一个团队来完成一个页面的开发。如何合理组织大量的javascript代码，使之具有良好的扩展性，能够适应需求的变化，使代码易于维护，是广大Web前端开发人员面临的一大挑战。
</p>
<p>纵观Web应用程序开发的历史，Web后端开发(PHP、J2EE、ASP.NET)与Web客户端开发的发展过程有一定的相似性，曾面临类似的问题。最初，Web程序功能简单，代码较少时，所有的控制、逻辑、UI展现代码混杂在一起；随着Web发展，程序规模变大，按原有方式开发出的程序显然不具有良好的结构，不利于大规模开发和后期维护，也不利于Web开发人员工作和角色的进一步细分，代码复用性差，瓶颈开始出现。Web后端程序设计者的解决方法是进行代码分类，将控制代码与展现代码开始分离， 于是Web后端开发从所谓的Model1发展到Model2；同时，传统桌面程序设计中的MVC(模型-视图-控制器)设计模式被引入，负责程序数据与逻辑计算的部分进一步分离出来，形成了Web后端开发中的MVC开发模式。MVC设计模式贯穿了软件工程分而治之的思想，有效解决了Web后端程序设计中的代码组织和复用问题。采用同一设计模式(MVC)也使代码更容易被他人理解，保证代码可靠性；它使Web开发工作可以细分为业务逻辑开发和UI展现开发。因此，MVC也利于团队开发。那么，MVC设计思想是否也能应用在前端开发中解决相关问题呢？既然问题具有许多相似性，笔者沿着相同的解决思路来试图解决前端开发中的代码组织问题。
</p>
<h2>2.MVC设计模式<a name="2Mvc设计模式"> </a></h2>
<p>在提出本文提出的MCRV设计模式之前，有必要对其所基于的MVC设计模式进行阐述。
</p>
<p>MVC这个概念很早之前就被人提起[1]，它代表一种设计思想。MVC是Model-View-Conroller的缩写，即模型-视图-控制器。这种开发模式将一个应用程序分为三个部分，模型(model)实现商业逻辑，提供数据；视图(view)负责向用户呈现界面和接受用户交互；控制器(controller)则负责响应用户交互请求，对用户请求进行翻译，根据不同的请求调用模型，执行商业逻辑。控制器本质上是一个调度器 (dispatcher)，通过其包含的各个方法(action)来执行具体的商业逻辑。MVC各个部件以最小的耦合性协同工作，从而使程序具有良好的可扩展性和可维护性和复用性。
</p>
<p>MVC设计模式最开始被用于桌面程序设计，典型地用于相同的数据需要不同的用户交互界面的设计场景。在经典的MVC设计思想中，控制器负责响应用户事件，根据事件类型和参数调用模型或改变视图。每个模型对应一个或者多个视图，当模型被控制器调用而得到改变时，模型向所有向其注册过的视图发送通知，视图根据从模型的中得到的信息改变外观。这种设计模式可以用图1表示。可以看出经典MVC设计模式中Controller、Model 都可以改变视图。</p>
<p style='text-align:center;'><img src="http://imgsrc.baidu.com/forum/pic/item/3bcf6f4f2e170269b2de0529.jpg" title="经典MVC" alt="经典MVC"/></p>
<p style='text-align:center;'>图1 经典MVC</p>
</p>
<p>基于MVC模式的Web开发(后端)一般可以用图2表示。在这种模式下，controller负责解析用户浏览器请求的URL，根据URL自动调用controller中的不同的Action响应用户请求。Action调用model，然后将model返回的数据填充到view中，view被返回给用户浏览器。Web服务端开发中典型的采用MVC模式的框架有CakePHP、Structs、Spring等等。</p>
<p style='text-align:center;'><img src="http://imgsrc.baidu.com/forum/pic/item/8a1ab90bdd976f5eb0351d29.jpg" title="Server端Web开发中的MVC" alt="Server端Web开发中的MVC"/></p>
<p style='text-align:center;'>图2 Server端Web开发中的MVC</p>
</p>
<p>相对于早期的经典MVC模式，Web开发中的MVC模式存在一些变化，因为对于一个桌面应用程序而言，可以很方便地将视图注册给模型，当模型数据发生改变时，即时通知视图页面发生改变；而对于Web应用而言，即使将多个页面注册给一个模型，当模型发生变化时，模型无法主动发送消息给Web页面（因为Web应用都是基于请求/响应模式的），只有当用户请求浏览该页面时，控制器才负责调用模型数据来更新Web页面。同时，Web开发中的MVC也比经典MVC具有更小的耦合性，因为Model不再与View发生交互，因此程序的结构更加良好，使Web前端开发和业务逻辑开发相分离变的简单。
</p>
<p>对于具有复杂交互逻辑和丰富界面的程序来说，MVC已被实践证明是一种行之有效的设计和开发思想。采用MVC设计模式的系统具有较好的结构，较低的耦合性，代码具有很好的维护性，能够适应复杂的业务逻辑和视图展现变化。它也非常适合团队开发，使开发人员分为不同的角色，专注于自己负责部分的开发。
</p>
<h2>3.MCRV设计模式<a name="3Mcrv设计模式"> </a></h2>
<p>综上所述，MVC是解决具有复杂交互界面、代码规模大的应用程序面临代码组织、复用问题的有效设计模式。基于此，本文尝试基于MVC设计思想解决前端开发中的类似问题。
</p>
<p>然而，在前端页面开发中不能直接套用MVC设计模式。因为，前端开发中的Web页面包含了HTML、CSS、Javascript等多个种类的代码，相对Web后端来说，Web页面整体就是一个负责UI展现、用户本地交互、发送服务请求的大View，与经典MVC及Web后端开发MVC模式中的View皆有不同。因此，需要具体问题具体分析。
</p>
<p>首先对Web页面中的HTML、CSS、Javascript等代码进一步分析，明确它们的具体功能分类。根据业界提出的Web开发标准，Web页首先被分为了内容-结构-表现-行为几个部分。内容、结构、表现是页面的静态部分，主要负责UI的展现，用户操作指令（键盘、鼠标）的接受，因此，内容、结构、表现属于视图 (View)的范畴。行为主要就是javascript代码，负责对用户操作指令的响应。在复杂ajax应用中， javascript代码的功能一般包括：响应用户指令，执行数据验证/处理、执行客户端交互逻辑，向服务器发送ajax请求，接受并处理服务器返回的数据，根据数据改变UI（向页面结构填充内容数据、变换样式等）。基于模型-视图-控制器分离的思想，Javascript代码中的数据验证/处理、本地业务逻辑计算、向服务器发请求获取数据的功能，对应模型(Model)的功能；响应(翻译)用户操作指令，根据指令执行业务逻辑处理的功能，属于控制器(Controller)的功能；而接受处理过的数据，根据数据修改页面的内容/结构/样式的功能既不属于控制器的功范畴，也不属于模型的功能范畴，这部分代码因为根据数据对View进行呈现(render)，可以命名为<em>Renderer</em>(<em>渲染器</em>或<em>呈现器</em>)。
</p>
<p>根据前述分析，本文提出了MCRV设计模式，如图3所示。阐述如下：
</p>
<div class="code">
<pre>   M(Model)：模型。完成数据验证、数据处理，执行客户端业务逻辑计算，或向服务器发起ajax请求调用服务端逻辑、接受返回的数据，将处理后的数据返回控制器。
   C(Controller)：控制器。控制器响应View上的事件，根据事件调度执行模型的业务逻辑，从业务逻辑获取返回数据，调度相应的渲染器(Render)来完成界面展现。在这个过程中控制器会有数据的传递：控制器调用模型中的逻辑时会传送Renderer搜集的数据(form表单各域的name/value、其他控制参数)，模型执行逻辑后返回作为执行结果的数据给控制器，控制器根据数据来调用渲染器(renderer)来完成界面呈现(rendering)，呈现(rendering)就是修改页面结构、内容和样式的过程。数据传递过程可以用图4表示。
   R(Renderer)：渲染器(呈现器)。渲染器被控制器调用，接受从控制器传递的数据，完成对界面的具体渲染。渲染器也负责控件(widget)的初始化，及建立Controller与具体事件的对应关系，事件发生时负责搜集View上的数据传送到Controller。
   V(View)：视图。视图是用户最终看到的整个Web界面，由结构、内容、样式（表现）等静态内容共同构成。View由Renderer进行初始化渲染和修改。
</pre>
</div>
<p>
<p style='text-align:center;'><img width="640" src="http://imgsrc.baidu.com/forum/pic/item/5f89f1fd866ab39cfd037fc6.jpg" title="MCRV开发模式" alt="MCRV开发模式"/></p>
<p style='text-align:center;'>图3:MCRV开发模式</p>
<p>   <br/> </p>
<p style='text-align:center;'><img width="640" src="http://imgsrc.baidu.com/forum/pic/item/9d776de6af9efc4eb8382029.jpg" title="数据传递过程" alt="数据传递过程"/></p>
<p style='text-align:center;'>图4：数据传递过程</p>
</p>
<p>可以看到在MCRV开发模式中，Controller处于控制中心的位置，Model完成具体的商业逻辑计算以及向后端发起ajax请求返回数据的功能。Controller与Model、Renderer之间的交互本质上数据交互的过程，它们之间存在着一个数据流，如图4所示。因此，制定Controller、Model、Renderer之间的交互接口时，数据格式定义很重要。
</p>
<h2>4.基于MCRV设计模式的Demo<a name="4基于Mcrv设计模式的Demo"> </a></h2>
<p>下面是一个用MCRV模式来开发的Demo页面，页面的功能是用表格展示和修改用户信息。javascript使用了jQuery库。页面界面如图5所示。页面代码在程序清单1中</p>
<p style='text-align:center;'><img width="640" src="http://imgsrc.baidu.com/forum/pic/item/ecddcb1e78c80102f724e4a4.jpg" title="基于MCRV设计模式的用户管理Demo" alt="基于MCRV设计模式的用户管理Demo"/></p>
<p style='text-align:center;'>图5：基于MCRV设计模式的用户管理Demo</p>
</p>
<p style='text-align:center;'>程序清单1</p>
<div class="code">
<pre><span class="cp">&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;</span>
<span class="nt">&lt;html&gt;</span>
<span class="nt">&lt;head&gt;</span>
    <span class="nt">&lt;meta</span> <span class="na">http-equiv=</span><span class="s">&quot;content-type&quot;</span> <span class="na">content=</span><span class="s">&quot;text/html;charset=utf-8&quot;</span><span class="nt">&gt;</span>
        <span class="nt">&lt;meta</span> <span class="na">http-equiv=</span><span class="s">&quot;X-UA-Compatible&quot;</span> <span class="na">content=</span><span class="s">&quot;IE=7&quot;</span> <span class="nt">/&gt;</span>
        <span class="nt">&lt;title&gt;</span>MCRV 设计模式 Demo<span class="nt">&lt;/title&gt;</span>
        <span class="nt">&lt;style </span><span class="na">type=</span><span class="s">&quot;text/css&quot;</span><span class="nt">&gt;</span>
            <span class="c">/********表现*********/</span>
            <span class="nt">table</span><span class="p">{</span><span class="k">width</span><span class="o">:</span><span class="m">100%</span><span class="p">;</span><span class="k">border-collapse</span><span class="o">:</span> <span class="k">collapse</span><span class="p">;}</span>
            <span class="nt">td</span><span class="p">{</span><span class="k">border</span><span class="o">:</span> <span class="m">1px</span> <span class="k">solid</span> <span class="nb">black</span><span class="p">;</span><span class="k">padding</span><span class="o">:</span> <span class="m">2px</span><span class="p">;}</span>
            <span class="nf">#container</span> <span class="p">{</span><span class="k">width</span><span class="o">:</span><span class="m">800px</span><span class="p">;</span><span class="k">margin</span><span class="o">:</span><span class="m">0px</span> <span class="k">auto</span><span class="p">;}</span>
            <span class="nf">#tbUsers</span><span class="p">{</span><span class="k">margin</span><span class="o">:</span><span class="m">20px</span> <span class="k">auto</span><span class="p">;}</span>
            <span class="nf">#tbUsers</span> <span class="nt">th</span><span class="p">{</span><span class="k">background-color</span><span class="o">:</span> <span class="nb">navy</span><span class="p">;</span><span class="k">color</span><span class="o">:</span><span class="nb">white</span><span class="p">;</span><span class="k">text-align</span><span class="o">:</span> <span class="k">center</span><span class="p">;</span><span class="k">vertical-align</span><span class="o">:</span> <span class="k">middle</span><span class="p">;</span><span class="k">border</span><span class="o">:</span><span class="m">1px</span> <span class="k">solid</span> <span class="nb">navy</span><span class="p">}</span>
             <span class="nf">#tbUsers</span> <span class="nt">td</span><span class="p">{</span><span class="k">text-align</span><span class="o">:</span> <span class="k">center</span><span class="p">;}</span>
            <span class="nc">.editCaption</span><span class="p">{</span><span class="k">width</span><span class="o">:</span><span class="m">100px</span><span class="p">;</span><span class="k">text-align</span><span class="o">:</span> <span class="k">right</span><span class="p">;}</span>
            <span class="nc">.buttonMargin</span><span class="p">{</span><span class="k">margin</span><span class="o">:</span><span class="m">0px</span> <span class="m">20px</span><span class="p">;}</span>
            <span class="nc">.buttonContainer</span><span class="p">{</span><span class="k">text-align</span><span class="o">:</span> <span class="k">center</span><span class="p">;</span><span class="k">vertical-align</span><span class="o">:</span> <span class="k">middle</span><span class="p">;</span><span class="k">height</span><span class="o">:</span><span class="m">50px</span><span class="p">}</span>
        <span class="nt">&lt;/style&gt;</span>
        <span class="nt">&lt;script </span><span class="na">src=</span><span class="s">&quot;./jquery-1.3.2.min.js&quot;</span> <span class="na">type=</span><span class="s">&quot;text/javascript&quot;</span> <span class="na">charset=</span><span class="s">&quot;utf-8&quot;</span><span class="nt">&gt;&lt;/script&gt;</span>
<span class="nt">&lt;/head&gt;</span>
<span class="nt">&lt;body&gt;</span>
    <span class="c">&lt;!-------结构---------&gt;</span>
    <span class="nt">&lt;div</span> <span class="na">id=</span><span class="s">&quot;container&quot;</span><span class="nt">&gt;</span>
        <span class="nt">&lt;table</span> <span class="na">id=</span><span class="s">&quot;tbUsers&quot;</span><span class="nt">&gt;</span>
            <span class="nt">&lt;thead&gt;&lt;th&gt;</span>id<span class="nt">&lt;/th&gt;&lt;th&gt;</span>姓名<span class="nt">&lt;/th&gt;&lt;th&gt;</span>年龄<span class="nt">&lt;/th&gt;&lt;th&gt;</span>修改<span class="nt">&lt;/th&gt;&lt;/thead&gt;</span>
            <span class="nt">&lt;tbody/&gt;</span>
        <span class="nt">&lt;/table&gt;</span>
        <span class="nt">&lt;div</span> <span class="na">style=</span><span class="s">&quot;display: none;&quot;</span> <span class="na">id=</span><span class="s">&quot;dvEditPanel&quot;</span><span class="nt">&gt;</span>
            <span class="nt">&lt;form</span> <span class="na">id=</span><span class="s">&quot;frmModify&quot;</span> <span class="na">name=</span><span class="s">&quot;frmModify&quot;</span><span class="nt">&gt;</span>
                <span class="nt">&lt;table&gt;</span>
                <span class="nt">&lt;tr&gt;</span>
                    <span class="nt">&lt;td</span> <span class="na">class=</span><span class="s">&quot;editCaption&quot;</span><span class="nt">&gt;</span> id: <span class="nt">&lt;/td&gt;</span>
                    <span class="nt">&lt;td&gt;&lt;span</span> <span class="na">id=</span><span class="s">&quot;spID&quot;</span><span class="nt">&gt;&lt;/span&gt;&lt;/td&gt;</span>
                <span class="nt">&lt;/tr&gt;</span>
                <span class="nt">&lt;tr&gt;</span>
                    <span class="nt">&lt;td</span> <span class="na">class=</span><span class="s">&quot;editCaption&quot;</span><span class="nt">&gt;</span> 姓名: <span class="nt">&lt;/td&gt;</span>
                    <span class="nt">&lt;td&gt;&lt;input</span> <span class="na">type=</span><span class="s">&quot;text&quot;</span> <span class="na">size=</span><span class="s">&quot;20&quot;</span> <span class="na">id=</span><span class="s">&quot;txtName&quot;</span><span class="nt">/&gt;&lt;/td&gt;</span>
                <span class="nt">&lt;/tr&gt;</span>
                <span class="nt">&lt;tr&gt;</span>
                    <span class="nt">&lt;td</span> <span class="na">class=</span><span class="s">&quot;editCaption&quot;</span><span class="nt">&gt;</span> 年龄: <span class="nt">&lt;/td&gt;</span>
                    <span class="nt">&lt;td&gt;&lt;input</span> <span class="na">type=</span><span class="s">&quot;text&quot;</span> <span class="na">size=</span><span class="s">&quot;20&quot;</span> <span class="na">id=</span><span class="s">&quot;txtAge&quot;</span><span class="nt">/&gt;&lt;/td&gt;</span>
                <span class="nt">&lt;/tr&gt;</span>
                <span class="nt">&lt;tr&gt;</span>
                    <span class="nt">&lt;td</span> <span class="na">colspan=</span><span class="s">&quot;2&quot;</span>  <span class="na">class=</span><span class="s">&quot;buttonContainer&quot;</span><span class="nt">&gt;</span>
                        <span class="nt">&lt;button</span> <span class="na">id=</span><span class="s">&quot;btnSubmitModify&quot;</span> <span class="na">class=</span><span class="s">&quot;buttonMargin&quot;</span> <span class="na">type=</span><span class="s">&quot;button&quot;</span><span class="nt">&gt;</span>提交<span class="nt">&lt;/button&gt;</span>
                        <span class="nt">&lt;button</span> <span class="na">id=</span><span class="s">&quot;btnCancelModify&quot;</span> <span class="na">class=</span><span class="s">&quot;buttonMargin&quot;</span> <span class="na">type=</span><span class="s">&quot;button&quot;</span><span class="nt">&gt;</span>取消<span class="nt">&lt;/button&gt;</span>
                    <span class="nt">&lt;/td&gt;</span>
                <span class="nt">&lt;/tr&gt;</span>
              <span class="nt">&lt;/table&gt;</span>
            <span class="nt">&lt;/form&gt;</span> 

        <span class="nt">&lt;/div&gt;</span>
    <span class="nt">&lt;/div&gt;</span>
    <span class="nt">&lt;script&gt;</span>
        <span class="c">/***************************行为********************************/</span> 

        <span class="kd">var</span> <span class="nx">UserManagerMCR</span><span class="o">;</span>
        <span class="nx">$</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span>
        <span class="p">{</span>
            <span class="nx">UserManagerMCR</span><span class="o">=</span><span class="k">new</span> <span class="nx">MCR</span><span class="p">(</span><span class="nx">UserController</span><span class="o">,</span><span class="nx">UserModel</span><span class="o">,</span><span class="nx">UserRenderer</span><span class="p">);</span>
        <span class="p">});</span> 

        <span class="c">/*</span>
<span class="c">         * MCR 三元组</span>
<span class="c">         */</span>
        <span class="kd">function</span> <span class="nx">MCR</span><span class="p">(</span><span class="nx">Controller</span><span class="o">,</span><span class="nx">Model</span><span class="o">,</span><span class="nx">Renderer</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="k">this</span><span class="p">.</span><span class="nx">controller</span><span class="o">=</span><span class="k">new</span> <span class="nx">Controller</span><span class="p">();</span>
            <span class="k">this</span><span class="p">.</span><span class="nx">model</span><span class="o">=</span><span class="k">new</span> <span class="nx">Model</span><span class="p">();</span>
            <span class="k">this</span><span class="p">.</span><span class="nx">renderer</span><span class="o">=</span><span class="k">new</span> <span class="nx">Renderer</span><span class="p">();</span>
            <span class="k">this</span><span class="p">.</span><span class="nx">controller</span><span class="p">.</span><span class="nx">model</span><span class="o">=</span><span class="k">this</span><span class="p">.</span><span class="nx">model</span><span class="o">;</span>
            <span class="k">this</span><span class="p">.</span><span class="nx">controller</span><span class="p">.</span><span class="nx">renderer</span><span class="o">=</span><span class="k">this</span><span class="p">.</span><span class="nx">renderer</span><span class="o">;</span>
            <span class="k">this</span><span class="p">.</span><span class="nx">model</span><span class="p">.</span><span class="nx">controller</span><span class="o">=</span><span class="k">this</span><span class="p">.</span><span class="nx">controller</span><span class="o">;</span>
            <span class="k">this</span><span class="p">.</span><span class="nx">renderer</span><span class="p">.</span><span class="nx">controller</span><span class="o">=</span><span class="k">this</span><span class="p">.</span><span class="nx">controller</span><span class="o">;</span>
            <span class="k">if</span><span class="p">(</span><span class="k">typeof</span> <span class="k">this</span><span class="p">.</span><span class="nx">model</span><span class="p">.</span><span class="nx">init</span><span class="o">==</span><span class="s2">&quot;function&quot;</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="k">this</span><span class="p">.</span><span class="nx">model</span><span class="p">.</span><span class="nx">init</span><span class="p">();</span>
            <span class="p">}</span>
            <span class="k">if</span><span class="p">(</span><span class="k">typeof</span> <span class="k">this</span><span class="p">.</span><span class="nx">renderer</span><span class="p">.</span><span class="nx">init</span><span class="o">==</span><span class="s2">&quot;function&quot;</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="k">this</span><span class="p">.</span><span class="nx">renderer</span><span class="p">.</span><span class="nx">init</span><span class="p">();</span>
            <span class="p">}</span>
            <span class="k">if</span><span class="p">(</span><span class="k">typeof</span> <span class="k">this</span><span class="p">.</span><span class="nx">controller</span><span class="p">.</span><span class="nx">init</span><span class="o">==</span><span class="s2">&quot;function&quot;</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="k">this</span><span class="p">.</span><span class="nx">controller</span><span class="p">.</span><span class="nx">init</span><span class="p">();</span>
            <span class="p">}</span>
        <span class="p">}</span> 

        <span class="c">/*</span>
<span class="c">         * 控制器</span>
<span class="c">         */</span>
        <span class="kd">function</span> <span class="nx">UserController</span><span class="p">()</span>
        <span class="p">{</span>
           <span class="k">this</span><span class="p">.</span><span class="nx">init</span><span class="o">=</span><span class="kd">function</span><span class="p">()</span>
            <span class="p">{</span>
                <span class="k">this</span><span class="p">.</span><span class="nx">initUserList</span><span class="p">();</span>
            <span class="p">}</span> 

            <span class="k">this</span><span class="p">.</span><span class="nx">initUserList</span><span class="o">=</span><span class="kd">function</span><span class="p">()</span>
            <span class="p">{</span>
                <span class="kd">var</span> <span class="nx">list</span><span class="o">=</span><span class="k">this</span><span class="p">.</span><span class="nx">model</span><span class="p">.</span><span class="nx">getUserList</span><span class="p">();</span>
                <span class="k">this</span><span class="p">.</span><span class="nx">renderer</span><span class="p">.</span><span class="nx">renderUserList</span><span class="p">(</span><span class="nx">list</span><span class="p">);</span>
            <span class="p">}</span> 

            <span class="k">this</span><span class="p">.</span><span class="nx">beginModify</span><span class="o">=</span><span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="kd">var</span> <span class="nx">user</span><span class="o">=</span><span class="k">this</span><span class="p">.</span><span class="nx">model</span><span class="p">.</span><span class="nx">getUserByID</span><span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nx">id</span><span class="p">);</span>
                <span class="k">this</span><span class="p">.</span><span class="nx">renderer</span><span class="p">.</span><span class="nx">showModifyUI</span><span class="p">(</span><span class="nx">user</span><span class="p">);</span>
            <span class="p">}</span> 

            <span class="c">//提交修改</span>
            <span class="k">this</span><span class="p">.</span><span class="nx">submitModify</span><span class="o">=</span><span class="kd">function</span><span class="p">(</span><span class="nx">user</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="kd">var</span> <span class="nx">result</span><span class="o">=</span><span class="k">this</span><span class="p">.</span><span class="nx">model</span><span class="p">.</span><span class="nx">modifyUser</span><span class="p">(</span><span class="nx">user</span><span class="p">);</span>
                <span class="k">if</span><span class="p">(</span><span class="nx">result</span><span class="p">.</span><span class="nx">success</span><span class="p">)</span>
                <span class="p">{</span>
                    <span class="kd">var</span> <span class="nx">list</span><span class="o">=</span><span class="k">this</span><span class="p">.</span><span class="nx">model</span><span class="p">.</span><span class="nx">getUserList</span><span class="p">();</span>
                    <span class="k">this</span><span class="p">.</span><span class="nx">renderer</span><span class="p">.</span><span class="nx">renderUIWhenSubmitModifySuccess</span><span class="p">(</span><span class="nx">list</span><span class="p">);</span>
                <span class="p">}</span>
                <span class="k">else</span>
                <span class="p">{</span>
                    <span class="nx">alert</span><span class="p">(</span><span class="nx">result</span><span class="p">.</span><span class="nx">msg</span><span class="p">);</span>
                <span class="p">}</span>
            <span class="p">}</span> 

            <span class="c">//取消修改</span>
            <span class="k">this</span><span class="p">.</span><span class="nx">cancelModify</span><span class="o">=</span><span class="kd">function</span><span class="p">()</span>
            <span class="p">{</span>
                <span class="k">this</span><span class="p">.</span><span class="nx">renderer</span><span class="p">.</span><span class="nx">hideModifyUI</span><span class="p">();</span>
            <span class="p">}</span> 

        <span class="p">}</span> 

        <span class="c">/*</span>
<span class="c">         * 模型</span>
<span class="c">         */</span>
        <span class="kd">function</span> <span class="nx">UserModel</span><span class="p">()</span>
        <span class="p">{</span>
            <span class="c">//模拟的数据，实际应用中经常从服务器获取</span> 

           <span class="k">this</span><span class="p">.</span><span class="nx">init</span><span class="o">=</span><span class="kd">function</span><span class="p">()</span>
           <span class="p">{</span>
              <span class="k">this</span><span class="p">.</span><span class="nx">data</span> <span class="o">=</span> <span class="p">[</span>
                <span class="p">{</span><span class="nx">id</span><span class="o">:</span><span class="mi">0</span><span class="o">,</span><span class="nx">name</span><span class="o">:</span><span class="s2">&quot;John&quot;</span><span class="o">,</span><span class="nx">age</span><span class="o">:</span><span class="mi">22</span><span class="p">}</span><span class="o">,</span>
                <span class="p">{</span><span class="nx">id</span><span class="o">:</span><span class="mi">1</span><span class="o">,</span><span class="nx">name</span><span class="o">:</span><span class="s2">&quot;Tom&quot;</span><span class="o">,</span><span class="nx">age</span><span class="o">:</span><span class="mi">30</span><span class="p">}</span><span class="o">,</span>
                <span class="p">{</span><span class="nx">id</span><span class="o">:</span><span class="mi">2</span><span class="o">,</span><span class="nx">name</span><span class="o">:</span><span class="s2">&quot;Tony&quot;</span><span class="o">,</span><span class="nx">age</span><span class="o">:</span><span class="mi">25</span><span class="p">}</span>
               <span class="p">];</span>
           <span class="p">}</span> 

            <span class="c">//获得用户数据列表</span>
            <span class="k">this</span><span class="p">.</span><span class="nx">getUserList</span><span class="o">=</span><span class="kd">function</span><span class="p">()</span>
            <span class="p">{</span>
                <span class="c">//todo ,可能ajax从后端返回</span>
                <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">data</span><span class="o">;</span>
            <span class="p">}</span> 

            <span class="c">//获得用户数据</span>
            <span class="k">this</span><span class="p">.</span><span class="nx">getUserByID</span><span class="o">=</span><span class="kd">function</span><span class="p">(</span><span class="nx">id</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="kd">var</span> <span class="nx">ix</span><span class="o">;</span>
                <span class="nx">$</span><span class="p">.</span><span class="nx">each</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">data</span><span class="o">,</span><span class="kd">function</span><span class="p">(</span><span class="nx">i</span><span class="o">,</span><span class="nx">item</span><span class="p">){</span><span class="k">if</span><span class="p">(</span><span class="nx">item</span><span class="p">[</span><span class="s2">&quot;id&quot;</span><span class="p">]</span><span class="o">==</span><span class="nx">id</span> <span class="p">)</span> <span class="p">{</span> <span class="nx">ix</span><span class="o">=</span><span class="nx">i</span><span class="o">;</span> <span class="k">return</span> <span class="kc">false</span><span class="o">;</span><span class="p">}});</span>
                <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">data</span><span class="p">[</span><span class="nx">ix</span><span class="p">];</span>
            <span class="p">}</span> 

            <span class="c">//修改用户数据</span>
            <span class="k">this</span><span class="p">.</span><span class="nx">modifyUser</span><span class="o">=</span><span class="kd">function</span><span class="p">(</span><span class="nx">user</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="kd">var</span> <span class="nx">result</span><span class="o">=</span><span class="p">{</span><span class="nx">success</span><span class="o">:</span><span class="kc">true</span><span class="o">,</span><span class="nx">msg</span><span class="o">:</span><span class="s2">&quot;修改成功&quot;</span><span class="p">};</span>
                <span class="c">//todo,验证参数user</span>
                <span class="c">//todo,修改用户数据</span>
                <span class="nx">$</span><span class="p">.</span><span class="nx">each</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">data</span><span class="o">,</span><span class="kd">function</span><span class="p">(</span><span class="nx">i</span><span class="o">,</span><span class="nx">item</span><span class="p">)</span>
                <span class="p">{</span>
                    <span class="k">if</span><span class="p">(</span><span class="nx">item</span><span class="p">[</span><span class="s2">&quot;id&quot;</span><span class="p">]</span><span class="o">==</span><span class="nx">user</span><span class="p">[</span><span class="s2">&quot;id&quot;</span><span class="p">])</span>
                    <span class="p">{</span>
                        <span class="nx">item</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">]</span><span class="o">=</span><span class="nx">user</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">];</span>
                        <span class="nx">item</span><span class="p">[</span><span class="s2">&quot;age&quot;</span><span class="p">]</span><span class="o">=</span><span class="nx">user</span><span class="p">[</span><span class="s2">&quot;age&quot;</span><span class="p">]</span>
                        <span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
                    <span class="p">}</span>
                <span class="p">});</span>
                <span class="k">return</span> <span class="nx">result</span><span class="o">;</span>
            <span class="p">}</span> 

        <span class="p">}</span> 

        <span class="c">/*</span>
<span class="c">         * 渲染器</span>
<span class="c">         */</span>
        <span class="kd">function</span> <span class="nx">UserRenderer</span><span class="p">()</span>
        <span class="p">{</span>
            <span class="k">this</span><span class="p">.</span><span class="nx">init</span><span class="o">=</span><span class="kd">function</span><span class="p">()</span>
            <span class="p">{</span>
                 <span class="kd">var</span> <span class="nx">me</span><span class="o">=</span><span class="k">this</span><span class="o">;</span>
                 <span class="nx">$</span><span class="p">(</span><span class="s2">&quot;#btnSubmitModify&quot;</span><span class="p">).</span><span class="nx">click</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span>
                 <span class="p">{</span>
                     <span class="kd">var</span> <span class="nx">user</span><span class="o">=</span><span class="p">{</span><span class="nx">id</span><span class="o">:</span><span class="nx">$</span><span class="p">(</span><span class="s2">&quot;#spID&quot;</span><span class="p">).</span><span class="nx">text</span><span class="p">()</span><span class="o">,</span><span class="nx">name</span><span class="o">:</span><span class="nx">$</span><span class="p">(</span><span class="s2">&quot;#txtName&quot;</span><span class="p">).</span><span class="nx">val</span><span class="p">()</span><span class="o">,</span><span class="nx">age</span><span class="o">:</span><span class="nx">$</span><span class="p">(</span><span class="s2">&quot;#txtAge&quot;</span><span class="p">).</span><span class="nx">val</span><span class="p">()};</span>
                     <span class="nx">me</span><span class="p">.</span><span class="nx">controller</span><span class="p">.</span><span class="nx">submitModify</span><span class="p">(</span><span class="nx">user</span><span class="p">);</span>
                 <span class="p">});</span>
                 <span class="nx">$</span><span class="p">(</span><span class="s2">&quot;#btnCancelModify&quot;</span><span class="p">).</span><span class="nx">click</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span>
                 <span class="p">{</span>
                     <span class="nx">me</span><span class="p">.</span><span class="nx">controller</span><span class="p">.</span><span class="nx">cancelModify</span><span class="p">();</span>
                 <span class="p">});</span>
                 <span class="nx">$</span><span class="p">(</span><span class="s2">&quot;#tbUsers .modify&quot;</span><span class="p">).</span><span class="nx">live</span><span class="p">(</span><span class="s2">&quot;click&quot;</span><span class="o">,</span><span class="kd">function</span><span class="p">()</span>
                 <span class="p">{</span>
                     <span class="kd">var</span> <span class="nx">id</span><span class="o">=</span><span class="nx">$</span><span class="p">(</span><span class="k">this</span><span class="p">).</span><span class="nx">attr</span><span class="p">(</span><span class="s2">&quot;uid&quot;</span><span class="p">);</span>
                     <span class="nx">me</span><span class="p">.</span><span class="nx">controller</span><span class="p">.</span><span class="nx">beginModify</span><span class="p">({</span><span class="s2">&quot;id&quot;</span><span class="o">:</span><span class="nx">id</span><span class="p">});</span>
                 <span class="p">});</span>
            <span class="p">}</span> 

            <span class="k">this</span><span class="p">.</span><span class="nx">renderUserList</span><span class="o">=</span><span class="kd">function</span><span class="p">(</span><span class="nx">list</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="kd">var</span> <span class="nx">htm</span><span class="o">=</span><span class="p">[];</span>
                <span class="k">for</span><span class="p">(</span><span class="kd">var</span> <span class="nx">ix</span><span class="o">=</span><span class="mi">0</span><span class="o">;</span><span class="nx">ix</span><span class="o">&lt;</span><span class="nx">list</span><span class="p">.</span><span class="nx">length</span><span class="o">;</span><span class="nx">ix</span><span class="o">++</span><span class="p">)</span>
                <span class="p">{</span>
                    <span class="nx">htm</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="s2">&quot;&lt;tr&gt;&lt;td&gt;&quot;</span> <span class="o">+</span><span class="nx">list</span><span class="p">[</span><span class="nx">ix</span><span class="p">][</span><span class="s2">&quot;id&quot;</span><span class="p">]</span><span class="o">+</span><span class="s2">&quot;&lt;/td&gt;&quot;</span> <span class="o">+</span><span class="s2">&quot;&lt;td&gt;&quot;</span><span class="o">+</span><span class="nx">list</span><span class="p">[</span><span class="nx">ix</span><span class="p">][</span><span class="s2">&quot;name&quot;</span><span class="p">]</span><span class="o">+</span><span class="s2">&quot;&lt;td&gt;&quot;</span><span class="o">+</span><span class="nx">list</span><span class="p">[</span><span class="nx">ix</span><span class="p">][</span><span class="s2">&quot;age&quot;</span><span class="p">]</span><span class="o">+</span><span class="s2">&quot;&lt;/td&gt;&quot;</span>
                        <span class="o">+</span><span class="s2">&quot;&lt;td&gt;&quot;</span><span class="o">+</span><span class="s2">&quot;&lt;a class=&#39;modify&#39; href=&#39;javascript:void(0)&#39; uid=&#39;&quot;</span><span class="o">+</span><span class="nx">list</span><span class="p">[</span><span class="nx">ix</span><span class="p">][</span><span class="s2">&quot;id&quot;</span><span class="p">]</span><span class="o">+</span><span class="s2">&quot;&#39;&gt;修改&lt;/a&gt;&lt;/td&gt;&quot;</span><span class="o">+</span><span class="s2">&quot;&lt;/tr&gt;&quot;</span><span class="p">);</span>
                <span class="p">}</span>
                <span class="nx">$</span><span class="p">(</span><span class="s2">&quot;#tbUsers&quot;</span><span class="p">).</span><span class="nx">children</span><span class="p">(</span><span class="s2">&quot;tbody&quot;</span><span class="p">).</span><span class="nx">html</span><span class="p">(</span><span class="nx">htm</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="p">));</span>
            <span class="p">}</span> 

            <span class="k">this</span><span class="p">.</span><span class="nx">showModifyUI</span><span class="o">=</span><span class="kd">function</span><span class="p">(</span><span class="nx">user</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="nx">$</span><span class="p">(</span><span class="s2">&quot;#dvEditPanel&quot;</span><span class="p">).</span><span class="nx">show</span><span class="p">();</span>
                <span class="nx">$</span><span class="p">(</span><span class="s2">&quot;#spID&quot;</span><span class="p">).</span><span class="nx">text</span><span class="p">(</span><span class="nx">user</span><span class="p">[</span><span class="s2">&quot;id&quot;</span><span class="p">]);</span>
                <span class="nx">$</span><span class="p">(</span><span class="s2">&quot;#txtName&quot;</span><span class="p">).</span><span class="nx">val</span><span class="p">(</span><span class="nx">user</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">]);</span>
                <span class="nx">$</span><span class="p">(</span><span class="s2">&quot;#txtAge&quot;</span><span class="p">).</span><span class="nx">val</span><span class="p">(</span><span class="nx">user</span><span class="p">[</span><span class="s2">&quot;age&quot;</span><span class="p">]);</span>
            <span class="p">}</span> 

            <span class="k">this</span><span class="p">.</span><span class="nx">hideModifyUI</span><span class="o">=</span><span class="kd">function</span><span class="p">()</span>
            <span class="p">{</span>
                <span class="nb">document</span><span class="p">.</span><span class="nx">frmModify</span><span class="p">.</span><span class="nx">reset</span><span class="p">();</span>
                <span class="nx">$</span><span class="p">(</span><span class="s2">&quot;#dvEditPanel&quot;</span><span class="p">).</span><span class="nx">hide</span><span class="p">();</span>
            <span class="p">}</span> 

            <span class="k">this</span><span class="p">.</span><span class="nx">renderUIWhenSubmitModifySuccess</span><span class="o">=</span><span class="kd">function</span><span class="p">(</span><span class="nx">list</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="k">this</span><span class="p">.</span><span class="nx">hideModifyUI</span><span class="p">();</span>
                <span class="k">this</span><span class="p">.</span><span class="nx">renderUserList</span><span class="p">(</span><span class="nx">list</span><span class="p">);</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="nt">&lt;/script&gt;</span>
<span class="nt">&lt;/body&gt;</span>
<span class="nt">&lt;/html&gt;</span>
</pre>
</div>
<h2>5.基于MCRV模式的开发框架原型<a name="5基于Mcrv模式的开发框架原型"> </a></h2>
<h3>5.1基本设计思想<a name="51基本设计思想"> </a></h3>
<p>框架是在一个特定的问题领域内，应用程序的部分设计与实现[2]。框架与设计模式通常是精密结合的。框架规定了应用的体系结构，使基于特定设计模式的开发能够复用公共代码；反之，框架强调设计复用，框架设计也基本上使用了设计模式，掌握了框架的设计模式可以快速掌握基于框架的应用程序开发。因此，使用MCRV设计模式进行前端开发时最好有一个与之配合的javascript框架。<br />
   基本设计考虑：
</p>
<p>   Model、Controller、Renderer组成一个三元组MCR，一个MCR三元组中Controller对象、Model对象和Renderer对象是唯一的。
</p>
<p>   Model、Controller、Renderer可以初始化和销毁
</p>
<p>   Controller、Model、View在需要时可以透明地引用其他对象
</p>
<p>   数据与逻辑分离，支持数据本地存储
</p>
<p>   一个Web页面可以有多个MCR组，即可以有多个Controller、Model、Renderer三元组分别完成不同的控制、逻辑、展现。这为一个页面逻辑和交互非常复杂时，拆分为多个模块，由多人开发提供了支持。
</p>
<h3>5.2 基本对象及其关系<a name="52基本对象及其关系"> </a></h3>
<p>下面是一个基于上述考虑的基于MCRV设计模式的javascript框架原型（以下简称MCRV框架）。<br />
   框架的基本对象：MCR、Model、Controller、Renderer、Cache。如图6所示。</p>
<p style='text-align:center;'><img src="http://imgsrc.baidu.com/forum/pic/item/86c21c2c06714355359bf73e.jpg" title="图6 基于MCRV模式的框架原型" alt="图6 基于MCRV模式的框架原型"/></p>
<p style='text-align:center;'>图6 基于MCRV模式的框架原型</p>
</p>
<p>   MCR：控制器(Controller)对象、模型对象(Model)和渲染器对象(Renderer)的复合对象。<br /> <br />
<span style='padding-left:45px;'>-Dispose()方法：执行MCR销毁操作，避免javascript内存泄露；在页面unload时自动调用；这个方法自动调用Model、Controller和Renderer的dispose()方法</span><br /> <br />
<span style='padding-left:45px;'>-model属性：包含的模型</span><br /> <br />
<span style='padding-left:45px;'>-controller属性：包含的控制器</span><br />
   <span style='padding-left:45px;'>-renderer属性：包含的渲染器</span>
</p>
<p>   Model：模型对象。<br /> <br />
<span style='padding-left:45px;'>-init()方法：执行模型初始化</span>  <br /> <br />
<span style='padding-left:45px;'>-dispose()方法：执行对象销毁,释放资源</span>  <br /> <br />
<span style='padding-left:45px;'>-cahce属性：数据的缓存。</span>
</p>
<p>   Controller：控制器对象<br /> <br />
<span style='padding-left:45px;'>-init()方法：执行控制器初始化</span> <br /> <br />
<span style='padding-left:45px;'>-dispose()方法：执行对象销毁,释放资源</span> <br /> <br />
<span style='padding-left:45px;'>-model属性：调度的模型</span> <br /> <br />
<span style='padding-left:45px;'>-renderer属性：控制的渲染器</span>
</p>
<p>   Renderer：渲染器对象  <br /> <br />
<span style='padding-left:45px;'>-init()方法：执行渲染器初始化</span> <br /> <br />
<span style='padding-left:45px;'>-dispose()方法：执行对象销毁，释放资源</span> <br /> <br />
<span style='padding-left:45px;'>-controller属性：对controller的引用</span>
</p>
<p>   Cache：基于key-value的缓存对象  <br /> <br />
<span style='padding-left:45px;'>-get()方法：基于键值获取缓存数据</span> <br /> <br />
<span style='padding-left:45px;'>-set()方法：设置缓存数据</span> <br /> <br />
<span style='padding-left:45px;'>-remove()方法：删除对应某个键值的缓存</span> <br /> <br />
<span style='padding-left:45px;'>-size()：缓存数量</span>
</p>
<h3>5.3 MCRV框架与其他web其他部分的关系<a name="53Mcrv框架与其他Web其他部分的关系"> </a></h3>
<p>基于MCRV模式的开发框架与Web页面开发其他组成部分的关系可以用图7表示。MCRV框架搭建起了js应用程序整体的结构，提供了应用程序上下文环境。MCRV框架可以与js组件库、css基础样式库和js业务逻辑组件一起作为应用程序构建的基础，并且它们之间没有依赖关系。尽管应用程序可以在js基础库（如jQuery）上开发，但是MCRV框架不依赖这些库。</p>
<p style='text-align:center;'><img src="http://imgsrc.baidu.com/forum/pic/item/fd4e946f329182ba80cb4a37.jpg" title="图7 基于MCRV模式的开发框架与其他Web页其他部分的关系" alt="图7 基于MCRV模式的开发框架与其他Web页其他部分的关系"/></p>
<p style='text-align:center;'>图7 基于MCRV模式的开发框架与其他Web页其他部分的关系</p>
</p>
<h2>6.结论<a name="6结论"> </a></h2>
<p>实践表明，MCRV设计模式能够有效解决复杂ajax开发中面临的问题，可以使Web页面代码结构良好，降低javascript代码的耦合性，提高复用性、适应性和灵活性，使Web页更加易于维护和重构。
</p>
<h2>参考文献<a name="参考文献"> </a></h2>
<p>[1]. Trygve Reenskaug Taskon.Working with objects in the user interfaces.
</p>
<p>[2]. J. Van Gurp, J. Bosch.Design, Implementation and Evolution of Object Oriented Frameworks Concepts and Guidelines.pdf.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.baiduux.com/blog/2011/07/08/frontend-mcrv-design-pattern/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Velocity 2011会议分享</title>
		<link>http://www.baiduux.com/blog/2011/06/30/velocity-2011/</link>
		<comments>http://www.baiduux.com/blog/2011/06/30/velocity-2011/#comments</comments>
		<pubDate>Thu, 30 Jun 2011 06:12:20 +0000</pubDate>
		<dc:creator>nwind</dc:creator>
				<category><![CDATA[前端探索]]></category>

		<guid isPermaLink="false">http://www.baiduux.com/blog/?p=1098</guid>
		<description><![CDATA[感谢公司和部门的支持，6月12号我和其它同事一起前往美国参加了Velocity 2011的会议，在此期间学习到了很多性能优化方面的经验和方法，通过本文整理出来分享给大家。



启程 
我们乘坐12号下午4点的国航飞机出发，经过11小时到达了旧金山国际机场，由于时差的关系，到了旧金山后的当地时间是12号中午12点，感觉像穿越了。

下飞机后我们租了2辆车，在美国租车是最经济方便的交通工具，因为地广人稀，除了大城市其它地方都很少见到公交和出租车，导航仪很精确，很顺利就从机场开到了宾馆。

参观Facebook总部 

13号我们参观了公司在Cupertino的办公室，然后在HR的带领下驱车前往Facebook总部进行参观，Facebook内部不大，只有2层办公室，里面的场景和电影social network中见到的一样，不像想象中的吵，但也不安静，很多人都戴着耳麦，由于签署了保密协议不能拍照片，感兴趣的同学可以观看Facebook官方的MTV Diary of Facebook，幸运的是我们在办公室里还见到了Mark。

然后我们在一个会议室里和2位Facebook工程师简单进行了交流，对Facebook最大的感受就是其内部的小巧和高效，像一个小公司一样在运作，每个工程师都可以自由修改任何Facebook的代码（当然，会有code review和自动化测试才能上线），Facebook有健全的小流量测试机制来不断改进产品，任何人都能提需求，然后通过对比测试来决定某个功能是否大规模部署，他们没有专门的QA，而是由工程师自己来保证质量。

保持小巧是Facebook高效率运作的一个重要原因，目前Facebook的工程师只有500人左右，而且他们不想增长太快。在这次Velocity大会上Jonathan的演讲也提到了Facebook的内部的工程师文化：small and hungry，在对php进行优化时他们最终选择hiphop这个高风险但高收益的方案，感觉很少有大公司会这么激进。

之前网上有篇文章How Facebook Ships Code谈到了Facebook内部运作的很多细节，感兴趣的同学可以阅读，与传统的企业相比确实有很多值得借鉴的地方。



6月14号的workshop 
由于每个分会场的人都太多了（超过400），第一天的workshop基本上相当于演讲，之前还以为主要是动手实验。

接下来我会列举出每个session相关的信息，大家可以点击session标题浏览详细的信息，其中大部分session都有slide可以下载，有些还有视频（youtube），而对于还没有视频的session请耐心等待一段时间。

Performance Tools
这个session主要介绍了4个性能优化相关的工具：WebPagetest、Mobitest、ShowSlow、dynatrace。

首先介绍的是WebPagetest，这是google员工Patrick Meenan全职开发的性能监测工具，它可以通过截图来直观地看到页面加载的过程，并能进行视频对比，方便演示性能优化结果，WebPagetest是目前功能最全面的开源监测工具，还可以部署到本地机器，方便进行内部的性能测试。

Mobitest是专门用来测试iOS和android页面性能的在线服务，可以在线免费使用，但由于移动设备的局限性（性能、相关工具），能监测到的信息要比桌面上的少。它的实现原理是在这些移动设备上运行一个自己开发的app，监听服务器的指令然后调用内嵌的webkit来监测页面性能。

ShowSlow是一个聚合YSlow、Page Speed、dynaTrace测试结果的平台，方便浏览，并能查看历史数据，它的实现方法是通过收集beacons结果。

dynatrace AJAX就不用多介绍了，它目前最强大的页面性能监测工具，可以详细列出页面渲染中详细的信息，甚至是每个函数的执行时间。

Analyzing the Performance of Mobile Web
Ariya的这个演讲是这次会议最好的演讲之一，因为Ariya是WebKit的reviewer之一，他对WebKit有深入的研究，提供了不少移动设备如何进行性能优化的思路，以下是我总结的要点：



     监测移动设备性能的方法


     源码注入方式，在相关部分加上日志，可以得到最详细的数据，但需要重新编译
 

     通过代理的方式，类似Fiddle 2，不过有局限
 

     通过高速摄像头，可以方便得到视觉效果，而且不影响运行的性能，但不能得到更多的数据，且不好进行分析
 



     PhantomJS


   [...]]]></description>
			<content:encoded><![CDATA[<p>感谢公司和部门的支持，6月12号我和其它同事一起前往美国参加了<a href="http://velocityconf.com">Velocity 2011</a>的会议，在此期间学习到了很多性能优化方面的经验和方法，通过本文整理出来分享给大家。
</p>
<p><img src="http://imgsrc.baidu.com/forum/mpic/item/844bce021cbe2c8c09fa934b.jpg" alt="velocity"/>
</p>
<h2>启程<a name="启程"> </a></h2>
<p>我们乘坐12号下午4点的国航飞机出发，经过11小时到达了旧金山国际机场，由于时差的关系，到了旧金山后的当地时间是12号中午12点，感觉像穿越了。
</p>
<p>下飞机后我们租了2辆车，在美国租车是最经济方便的交通工具，因为地广人稀，除了大城市其它地方都很少见到公交和出租车，导航仪很精确，很顺利就从机场开到了宾馆。
</p>
<h2>参观Facebook总部<a name="参观Facebook总部"> </a></h2>
<p><span id="more-1098"></span></p>
<p>13号我们参观了公司在Cupertino的办公室，然后在HR的带领下驱车前往Facebook总部进行参观，Facebook内部不大，只有2层办公室，里面的场景和电影social network中见到的一样，不像想象中的吵，但也不安静，很多人都戴着耳麦，由于签署了保密协议不能拍照片，感兴趣的同学可以观看Facebook官方的MTV <a href="http://www.verycd.com/topics/2887025/">Diary of Facebook</a>，幸运的是我们在办公室里还见到了Mark。
</p>
<p>然后我们在一个会议室里和2位Facebook工程师简单进行了交流，对Facebook最大的感受就是其内部的小巧和高效，像一个小公司一样在运作，每个工程师都可以自由修改任何Facebook的代码（当然，会有code review和自动化测试才能上线），Facebook有健全的小流量测试机制来不断改进产品，任何人都能提需求，然后通过对比测试来决定某个功能是否大规模部署，他们没有专门的QA，而是由工程师自己来保证质量。
</p>
<p>保持小巧是Facebook高效率运作的一个重要原因，目前Facebook的工程师只有500人左右，而且他们不想增长太快。在这次Velocity大会上Jonathan的演讲也提到了Facebook的内部的工程师文化：small and hungry，在对php进行优化时他们最终选择<a href="https://github.com/facebook/hiphop-php">hiphop</a>这个高风险但高收益的方案，感觉很少有大公司会这么激进。
</p>
<p>之前网上有篇文章<a href="http://framethink.wordpress.com/2011/01/17/how-facebook-ships-code/">How Facebook Ships Code</a>谈到了Facebook内部运作的很多细节，感兴趣的同学可以阅读，与传统的企业相比确实有很多值得借鉴的地方。
</p>
<p><img src="http://imgsrc.baidu.com/forum/mpic/item/379b83a0e920feeb4610644a.jpg" alt="facebook"/>
</p>
<h2>6月14号的workshop<a name="6月14号的Workshop"> </a></h2>
<p>由于每个分会场的人都太多了（超过400），第一天的workshop基本上相当于演讲，之前还以为主要是动手实验。
</p>
<p>接下来我会列举出每个session相关的信息，大家可以点击session标题浏览详细的信息，其中大部分session都有slide可以下载，有些还有视频（youtube），而对于还没有视频的session请耐心等待一段时间。
</p>
<h3><a href="http://velocityconf.com/velocity2011/public/schedule/detail/19771">Performance Tools</a></h3>
<p>这个session主要介绍了4个性能优化相关的工具：WebPagetest、Mobitest、ShowSlow、dynatrace。
</p>
<p>首先介绍的是<a href="http://www.webpagetest.org">WebPagetest</a>，这是google员工Patrick Meenan全职开发的性能监测工具，它可以通过截图来直观地看到页面加载的过程，并能进行视频对比，方便演示性能优化结果，WebPagetest是目前功能最全面的开源监测工具，还可以部署到本地机器，方便进行内部的性能测试。
</p>
<p><a href="http://www.blaze.io/mobile/">Mobitest</a>是专门用来测试iOS和android页面性能的在线服务，可以在线免费使用，但由于移动设备的局限性（性能、相关工具），能监测到的信息要比桌面上的少。它的实现原理是在这些移动设备上运行一个自己开发的app，监听服务器的指令然后调用内嵌的webkit来监测页面性能。
</p>
<p><a href="http://www.showslow.com/">ShowSlow</a>是一个聚合YSlow、Page Speed、dynaTrace测试结果的平台，方便浏览，并能查看历史数据，它的实现方法是通过收集<a href="http://developer.yahoo.com/yslow/help/beacons.html">beacons</a>结果。
</p>
<p><a href="http://ajax.dynatrace.com/ajax/en/">dynatrace AJAX</a>就不用多介绍了，它目前最强大的页面性能监测工具，可以详细列出页面渲染中详细的信息，甚至是每个函数的执行时间。
</p>
<h3><a href="http://velocityconf.com/velocity2011/public/schedule/detail/19967">Analyzing the Performance of Mobile Web</a></h3>
<p>Ariya的这个演讲是这次会议最好的演讲之一，因为Ariya是WebKit的reviewer之一，他对WebKit有深入的研究，提供了不少移动设备如何进行性能优化的思路，以下是我总结的要点：
</p>
<ul>
<li>
     监测移动设备性能的方法
<ul>
<li>
     源码注入方式，在相关部分加上日志，可以得到最详细的数据，但需要重新编译
 </li>
<li>
     通过代理的方式，类似Fiddle 2，不过有局限
 </li>
<li>
     通过高速摄像头，可以方便得到视觉效果，而且不影响运行的性能，但不能得到更多的数据，且不好进行分析
 </li>
</ul>
</li>
<li>
     PhantomJS
<ul>
<li>
     这是一个基于WebKit的命令行工具，可以在JS中调用WebKit引擎，方便进行自动化测试
 </li>
</ul>
</li>
<li>
     通过代码注入方式来监测性能
<ul>
<li>
     可以得到页面各元素渲染的顺序
 </li>
<li>
     可以得到细致的元素速度数据
 </li>
<li>
     JS引擎GC的情况
 </li>
<li>
     他采用的方法是修改android的代码，然后重新编译，在绘图部分打日志
 </li>
</ul>
</li>
<li>
     <a href="http://github.com/senchalabs/android-tools">android-tools</a>
<ul>
<li>
     android的Web类应用开发和调试工具，包括eventrecoder和remotejs
 </li>
<li>
     remotejs可以实用console.log来获取页面中的数据，执行js等，解决了如何方便调试的问题
 </li>
<li>
     eventrecoder可以用来进行android上web的单元测试
 </li>
</ul>
</li>
<li>
     <a href="https://github.com/senchalabs/hammerjs/">hammerjs</a>
<ul>
<li>
     一个JS的shell，基于v8实现，类似nodejs，不过功能要简单很多
 </li>
<li>
     其中有一个模块Reflect可以用来分析js的语法，它的实现居然是从JavaScriptCore中将解析部分剥离出来，生成的结果类似<a href="https://developer.mozilla.org/en/SpiderMonkey/Parser_API">SpiderMonkey</a>的parser，这个工具可以用来简化js相关分析工具的开发。
 </li>
</ul>
</li>
</ul>
<p>Ariya还提供了一些性能优化和需要注意的事项，如避免创建对象等，具体请参考其slide，建议大家等这个视频出来后都看一下。
</p>
<p>下面是其中的一页，整个slide做得相当漂亮
</p>
<p><img src="http://imgsrc.baidu.com/forum/mpic/item/c3b6ed2baca98efb023bf6ff.jpg" alt="ariya"/>
</p>
<h3><a href="http://velocityconf.com/velocity2011/public/schedule/detail/19976">Mobile Web &amp; HTML5 Performance Optimization</a></h3>
<p>整体来看这个session没有什么亮点，对于mobile web开发不太了解的同学可以看看，系统了解一下，演讲者写过很多书，比较善于整理和总结，但缺乏新意。
</p>
<h2>6月15号的会议<a name="6月15号的会议"> </a></h2>
<p>15号是velocity第一天的正式会议，sessions很多，整体时间也比14号长。
</p>
<h3><a href="http://velocityconf.com/velocity2011/public/schedule/detail/20141">JavaScript &amp; Metaperformance</a></h3>
<p>果然到处都能见到Douglas，这次除了介绍js语言特点以外还不忘鄙视了一下java，感兴趣的同学可以看看ppt。
</p>
<p>Douglas说现在的JS性能测试都是骗人的，除了<a href="http://research.microsoft.com/en-us/projects/jsmeter/">JSMeter</a>看上去还行。
</p>
<p>接下来是大家常听到的：DOM是瓶颈，大部分时间花在layout、painting等工作上，不要过早优化，避免导致代码不易维护。。。
</p>
<p>然后他说JS中还是有优秀部分的，顺带推广自己的书JavaScript: The Good Parts。
</p>
<p>最后忽悠大家用JSLint来作为性能监测工具，这。。。
</p>
<h3><a href="http://velocityconf.com/velocity2011/public/schedule/detail/20894">Testing and Monitoring Mobile Apps</a></h3>
<p>主要是Keynote产品的广告，不过做得很不错，介绍了Mobile Device Perspective 5，它是一个非常强大的手机测试工具，可以远程操作真实的iphone、android手机，还可以运行自动化脚本，监测应用性能等，是移动设备开发和性能优化的利器。
</p>
<p>但实现原理不清楚，怀疑是在越狱的手机上运行后台进程，大家可以通过看视频了解其功能，这是我15号上午印象最深的一个session，欢迎了解内幕的同学指教。
</p>
<h3><a href="http://velocityconf.com/velocity2011/public/schedule/detail/18184">Real-Time Real-Fast</a></h3>
<p>主要谈使用WebSocket来减少overhead，可以用于实时性要求高的场景，然后推广了一下dojo中的socket API，它可以简化WebSocket的开发，并自动fallback到传统的long-polling方式，其它没听到什么特别的。
</p>
<h3><a href="http://velocityconf.com/velocity2011/public/schedule/detail/18039">Performance Measurement and Case Studies at MSN</a></h3>
<p>MSN的工程师分享了在性能优化方面的经验和内部数据，我这边记的一些要点：
</p>
<ul>
<li>
     之前太过于关注下载时间等网络数据，缺乏对实际展现性能的关注
 </li>
<li>
     应该更多关注渲染及展现时间，并提议浏览器增加这些监测API
 </li>
<li>
     js越来越大了，要将js放底部或延迟加载及执行
 </li>
<li>
     延迟广告的加载，看上去他们的广告长宽是固定的，所以延迟是可行的
 </li>
<li>
     使用Data URL来显示缩率图，减少请求数
 </li>
</ul>
<p>建议简单看一下这个slide，里面有一些性能优化对比测试的数据。
</p>
<h3><a href="http://velocityconf.com/velocity2011/public/schedule/detail/21089">Improving Performance by Changing the Rules &#8211; From Fast to SPDY</a></h3>
<p>主要介绍了SPDY对http的优化对比，在3G网络下性能提升效果显著，看slide就好了，没太多可听的，虽然Google的ssl请求都支持SPDY了，但其它网站及少有支持的。
</p>
<h3><a href="http://velocityconf.com/velocity2011/public/schedule/detail/18241">Understanding Mobile Web Browser Performance</a></h3>
<p>主要内容是介绍了手机中的网络情况，手机为了节能，网络不会一直开启，所以初次打开时会有启动网络的时间，而且3G网络延迟还是很高，也许4G会好点。
</p>
<p>在android中只有4个线程来处理http请求，所以android中浏览器的并发不会超过4个。
</p>
<p>android中的浏览器默认打开了pipelining，是极少数默认开启这个技术的浏览器。
</p>
<h3><a href="http://velocityconf.com/velocity2011/public/schedule/detail/18135">10 Tricks for Mobile Performance</a></h3>
<p>介绍了针对移动设备进行性能优化的建议，具体内容建议看看slide就好了。
</p>
<h3><a href="http://velocityconf.com/velocity2011/public/schedule/detail/18087">Know Your Engines: How to Make Your JavaScript Fast</a></h3>
<p>重点推荐一下David的这个session，David是Mozilla的JS引擎工程师，之前在他的<a href="http://blog.mozilla.com/dmandelin/">blog</a>上学习到了很多JS引擎优化的细节，这次又有不少收获，建议对JS引擎实现不太了解的同学抽空听听这个session，可以学到很多知识。
</p>
<p>David首先讲解了JS引擎中的JIT和GC实现原理，然后介绍如何根据这些原理来优化JS代码，如避免动态改变对象的类型来优化JIT的执行、减小使用全局变量来减小GC、避免使用稀疏的数组等。
</p>
<h3><a href="http://velocityconf.com/velocity2011/public/schedule/detail/18229">Take it all off! Lossy Image Optimization</a></h3>
<p>主要针对如何优化图片这一主题，详细介绍了如何优化图片的大小，包括png、jpeg，有损、无损压缩等细节。通过一定程度的有损压缩，在性能和效果上进行权衡。
</p>
<p>从目前HTTP Archive的数据来看，图片是占带宽最多的部分（60%左右），对其进行优化可以明显减少带宽消耗。
</p>
<h3><a href="http://velocityconf.com/velocity2011/public/schedule/detail/17977">WebPagetest Update</a></h3>
<p>WebPagetest的作者Patrick详细介绍了WebPagetest这一年来的改进，包括：
</p>
<ul>
<li>
     支持dynaTrace
 </li>
<li>
     Web Page Replay
 </li>
<li>
     对外API
 </li>
<li>
     提供WPT Monitor来监控页面性能变化的情况
 </li>
</ul>
<p>建议关注这个性能优化工具。
</p>
<h2>6月16号的会议<a name="6月16号的会议"> </a></h2>
<h3><a href="http://velocityconf.com/velocity2011/public/schedule/detail/20204">Holistic Performance</a></h3>
<p>John介绍了jQuery中如何进行性能优化的，一些注意的点等：
</p>
<ul>
<li>
     需要进行全局考虑，运行快的代码有可能耗cpu和内存
 </li>
<li>
     用JS字典作为例子来解释性能优化需要考虑很多方面，包括文件大小、cpu、内存等，之前John在他的<a href="http://ejohn.org/blog/revised-javascript-dictionary-search/">blog上讨论过</a>
 </li>
<li>
     jQuery性能优化的准则：
<ul>
<li>
     通过<a href="http://jsperf.com">JSPerf</a>来测试优化效果，JSPerf基于<a href="http://benchmarkjs.com/">Benchmark.js</a>，是一个很优秀的JS性能测试工具，它通过很多方法来保证测试结果的准确性
 </li>
<li>
     考虑全局优化，细节优化意义不大，纯js的性能问题很少见，基本上都是DOM性能问题
 </li>
<li>
     保持简洁的代码，避免为了性能而减低可读性
 </li>
<li>
     保证IE的性能，即便IE是最慢的浏览器，但由于市场占用率高，IE的性能是最重要的
 </li>
</ul>
</li>
</ul>
<h3><a href="http://velocityconf.com/velocity2011/public/schedule/detail/20912">Making the Web Instant</a></h3>
<p>介绍了Chrome中的prerender，宣传视频很唬人，将原先需要等待6秒的页面降到了0秒，看来要是大家都用Chrome，咱们也没必要做性能优化了。
</p>
<h3>浏览器专栏<a name="浏览器专栏"> </a></h3>
<p>浏览器专栏和去年在北京的velocity类似，主要介绍浏览器的一些最新的进展，Chrome、Firefox、IE平时大家也都比较了解，所以没太多特别的地方。
</p>
<p>不过今年Opera首次出现，介绍了Opera的产品线，Opera在移动领域有两个版本，mini和mobile，mobile是全功能的，而mini的渲染是由服务端完成的，原来Opera还有一个<a href="http://www.opera.com/developer/tools/mobile/">模拟器</a>，可以用它来在桌面测试Opear mobile的展现效果。
</p>
<h3><a href="http://velocityconf.com/velocity2011/public/schedule/detail/17986">HTML5, Flash and the Battle for Faster Cat Videos</a></h3>
<p>来自YouTube的工程师介绍了YouTube中视频播放器的一些经验，并对HTML5中的video标签和Flash进行了对比，HTML5最大的优势是能和页面中的其它元素更好地结合，而Flash目前在性能上要比HTML5好，尤其是视频加载的速度。
</p>
<p>最后建议主要使用Flash，而专门针对iOS用户提供HTML5版本，因为iOS对YouTube API流量的贡献不小。
</p>
<h3><a href="http://velocityconf.com/velocity2011/public/schedule/detail/18407">The Impact of Ads on Performance and Improving Perceived Performance</a></h3>
<p>这个session我并没有听，不过从发出来的ppt看，内容还是不错的，介绍了Yahoo mail中如何改进广告加载来提高页面性能，有很多细节的技术方案。
</p>
<h2>参观Google总部<a name="参观Google总部"> </a></h2>
<p>17号我们前往位于Mountain View的Google总部进行了参观，正如传闻所说的，Google总部很大，里面人很多。
</p>
<p>看到了传说中的恐龙骨架、飞船、大Nexus One、全景Google map、沙滩排球场，比起facebook工位要宽敞不少，还有很多4人一间的房间，里面很安静，传说中空气净化开得很足也是真的，办公室里面空气质量很不错，关于Google总部的情况大家可以搜索相关的资料，网上说的基本上靠谱。
</p>
<p>Google总部里有很多餐厅，里面有各种风格的食物，还有中国、印度等不同地区的口味，比Facebook要大得多。
</p>
<p>这里感谢一下Tim在百忙中抽空带我们到处参观。
</p>
<p><img src="http://imgsrc.baidu.com/forum/mpic/item/b0d5ab5907c109be9d8204a2.jpg" alt="google"/>
</p>
<h2>整体感受<a name="整体感受"> </a></h2>
<p>这里零碎写下一些自己一些参会的感受：
</p>
<ul>
<li>
     和国内相比还是更容易遇到牛人，比如Ariya和David的两个session是我觉得收获最大的，但在国内很难听到这样深入的演讲
 </li>
<li>
     最头疼的问题是时差，上午11点就相当于北京夜里2点，影响了开会的效率
 </li>
<li>
     今年性能优化主题已经逐渐转向了自动化测试和持续集成，通过自动化的方法来保证性能
 </li>
<li>
     标准化也是一个很大趋势，beacons和HAR这两个标准都逐渐被大家接受
 </li>
<li>
     数据分析对性能优化来说至关重要，Facebook在这方面做得很专业，从他们招聘Web Optimization工程师的职位要求也能看得出来
 </li>
</ul>
<p>最后，除了开会，我们还抽空参观了漂亮的斯坦福大学：
</p>
<p><img src="http://imgsrc.baidu.com/forum/mpic/item/74deef89fa0e0bf4a5c2724a.jpg" alt="stanford"/>
</p>
<p><img src="http://imgsrc.baidu.com/forum/mpic/item/3bcf6f4f91da5d69b2de051b.jpg" alt="stanford2"/>
</p>
<p>最后去参观了宏伟的金门大桥，硅谷和旧金山的气候差距很大，忽然就变成阴云密布了：
</p>
<p><img src="http://imgsrc.baidu.com/forum/mpic/item/2f8c463f7b38455d71cf6c4a.jpg" alt="golden"/></p>
]]></content:encoded>
			<wfw:commentRss>http://www.baiduux.com/blog/2011/06/30/velocity-2011/feed/</wfw:commentRss>
		<slash:comments>18</slash:comments>
		</item>
		<item>
		<title>web前端课程课件汇总</title>
		<link>http://www.baiduux.com/blog/2011/06/23/fe-class-slides/</link>
		<comments>http://www.baiduux.com/blog/2011/06/23/fe-class-slides/#comments</comments>
		<pubDate>Thu, 23 Jun 2011 09:14:11 +0000</pubDate>
		<dc:creator>mbo</dc:creator>
				<category><![CDATA[web前端技术课程]]></category>
		<category><![CDATA[web前端课程]]></category>
		<category><![CDATA[课件]]></category>

		<guid isPermaLink="false">http://www.baiduux.com/blog/?p=1088</guid>
		<description><![CDATA[请各位同学注意，后续的课件将在本贴中汇总。
如果下载后发现后缀是php请改成pdf。
第一节课相关课件：
0.授课计划和项目要求
1.前端的美好时代.pdf
2.WEB前端技术程序员编程能力成长之路.pdf
课堂作业：



第二节课相关课件：
2.样式之美-Web前端课程体系之CSS.pdf
2.HTML5 – Web开发步入新阶段.pdf
第三节课相关课件
3.JS－行为控制语言+js架构思想.pdf
3.tangram设计思想.pdf
第四节课相关课件
4.百度地图API
4.百度web安全2.0

]]></description>
			<content:encoded><![CDATA[<p>请各位同学注意，后续的课件将在本贴中汇总。</p>
<p>如果下载后发现后缀是php请改成pdf。</p>
<p>第一节课相关课件：</p>
<p><a href="http://s3.bae.baidu.com:8080/baiduux/0.%CA%DA%BF%CE%BC%C6%BB%AE%BA%CD%CF%EE%C4%BF%D2%AA%C7%F3.pdf?sign=MBO:TzFtAKGMUE5K:tXE9vfQ4p7PfEikS0DOuvXN%2BHj4%3D">0.授课计划和项目要求</a></p>
<p><a href=" http://s3.bae.baidu.com:8080/baiduux/2.%C7%B0%B6%CB%B5%C4%C3%C0%BA%C3%CA%B1%B4%FA.pdf?sign=MBO:TzFtAKGMUE5K:E05fZa%2BtfO3OxSNJSfYF5Nxqftk%3D">1.前端的美好时代.pdf</a></p>
<p><a href="http://s3.bae.baidu.com:8080/baiduux/1.WEB%C7%B0%B6%CB%BC%BC%CA%F5%B3%CC%D0%F2%D4%B1%B1%E0%B3%CC%C4%DC%C1%A6%B3%C9%B3%A4%D6%AE%C2%B7.pptx.pdf?sign=MBO:TzFtAKGMUE5K:EX5Ky2%2B2bfGUAyWliyIh5tE09Rc%3D">2.WEB前端技术程序员编程能力成长之路.pdf</a></p>
<p>课堂作业：</p>
<p><a href="http://s3.bae.baidu.com:8080/baiduux/fdsafdsfsfdsf.jpg?sign=MBO:TzFtAKGMUE5K:HIPX1lPTOcboT7yBXj84z0%2BRoQM%3D"><img class="alignnone size-full wp-image-1417" title="作业-精简版" src="http://s3.bae.baidu.com:8080/baiduux/fdsafdsfsfdsf.jpg?sign=MBO:TzFtAKGMUE5K:HIPX1lPTOcboT7yBXj84z0%2BRoQM%3D" alt="" /></a></p>
<p><br class="spacer_" /></p>
<p><a href="http://s3.bae.baidu.com:8080/baiduux/wp-display-data%20%281%29.jpg?sign=MBO:TzFtAKGMUE5K:rUEF%2Bc6Z%2FtFfYmy84D0s9PdXiBw%3D"><img class="alignnone size-full wp-image-1416" title="作业-丰富版" src="http://s3.bae.baidu.com:8080/baiduux/wp-display-data%20%281%29.jpg?sign=MBO:TzFtAKGMUE5K:rUEF%2Bc6Z%2FtFfYmy84D0s9PdXiBw%3D" alt="" /></a></p>
<p>第二节课相关课件：</p>
<p><a href=" http://s3.bae.baidu.com:8080/baiduux/2.%D1%F9%CA%BD%D6%AE%C3%C0-Web%C7%B0%B6%CB%BF%CE%B3%CC%CC%E5%CF%B5%D6%AECSS.pdf?sign=MBO:TzFtAKGMUE5K:22cHm6f8Iyfco%2BpzB%2BFbv6UhKRs%3D">2.样式之美-Web前端课程体系之CSS.pdf</a></p>
<p><a href="http://s3.bae.baidu.com:8080/baiduux/2.HTML5%20%A8C%20Web%BF%AA%B7%A2%B2%BD%C8%EB%D0%C2%BD%D7%B6%CE.pdf?sign=MBO:TzFtAKGMUE5K:pRRHetSBvDXwEdrhpb2%2BmY4tTI8%3D">2.HTML5 – Web开发步入新阶段.pdf</a></p>
<p>第三节课相关课件</p>
<p><a href="http://s3.bae.baidu.com:8080/baiduux/3.Web%C7%B0%B6%CB%BF%CE%B3%CC%CC%E5%CF%B5%D6%AEJS%2BJS%BC%DC%B9%B9%CB%BC%CF%EB.pdf?sign=MBO:TzFtAKGMUE5K:%2B8gj40qRCYweCZ9bR9LadWJJ%2BHE%3D">3.JS－行为控制语言+js架构思想.pdf</a></p>
<p><a href="http://s3.bae.baidu.com:8080/baiduux/4.tangram%C9%E8%BC%C6%CB%BC%CF%EB.pdf?sign=MBO:TzFtAKGMUE5K:n3akDWcs%2BK1qrqdweLzQpYI%2FFbU%3D">3.<strong>tangram设计思想.pdf</strong></a></p>
<p>第四节课相关课件</p>
<p><a href="http://www.slideshare.net/TommyChang/api-8538710">4.百度地图API</a></p>
<p><a href="http://www.slideshare.net/TommyChang/web20-8538713">4.百度web安全2.0</a></p>
<p><br class="spacer_" /></p>
]]></content:encoded>
			<wfw:commentRss>http://www.baiduux.com/blog/2011/06/23/fe-class-slides/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>如何做到API兼容</title>
		<link>http://www.baiduux.com/blog/2011/06/21/javscript-api-compatible/</link>
		<comments>http://www.baiduux.com/blog/2011/06/21/javscript-api-compatible/#comments</comments>
		<pubDate>Tue, 21 Jun 2011 11:35:02 +0000</pubDate>
		<dc:creator>berg</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[前端技术]]></category>
		<category><![CDATA[api]]></category>

		<guid isPermaLink="false">http://www.baiduux.com/blog/?p=1083</guid>
		<description><![CDATA[本文主要介绍什么是API，以及API兼容的重要性，最终给出方案如何评估API，以及如何做到API兼容。]]></description>
			<content:encoded><![CDATA[<p>本文主要介绍什么是API，以及API兼容的重要性，最终给出方案如何评估API，以及如何做到API兼容。</p>
<h3>What&#8217;s API?</h3>
<p>API的全称是application programming interface。</p>
<p>而很多时候，程序开发者仅仅把函数、类的接口做为API的一部分，而忽略了其他重要的编程接口。</p>
<p>事实上，在前端Javscript编程中常见的API包括：</p>
<ul>
<li>函数、类接口，包括参数，返回值，函数对外部对象（常常是DOM）的具体操作等
<li>网络接口协议，如和后端交互的JSON、XML数据格式，或者script回调中的函数名
<li>样式以及HTML接口
<li>外部依赖（对浏览器具体特性的依赖）
<li>一些无意泄露的内部实现
</ul>
<p>越往后的API，越隐晦，越不容易受到重视，但是一旦这些API发生变化，可能会导致调用方出现不符合预期甚至程序直接报错的情况。<br />
<span id="more-1083"></span></p>
<h3>Why API cannot be changed?</h3>
<p>API是程序协同开发的重要保证，API的用户希望API的提供方提供的是一段功能明确、接口明了的程序。更重要的是，用户更期望在程序升级以后，他们能够“不经思考”地升级这些第三方代码。</p>
<p>一旦上述提到的5个API中的任何一个发生变化，可能会给他们带来巨大的代价，用户需要排查所有调用的代码，需要更改一些协议，需要调整所有与之相关的部分，这些工作对他们来说都是额外的，在预期之外的。如果辛辛苦苦完成这些以后，还在测试过程中发现了相关的bug，那对用户的打击就更大了。</p>
<p>如果API经常发生变化，用户就会失去对这段程序的信任，他们会更倾向自己获得源代码以后，按照自己的需求进行修改，自行维护一个内部的API比调用一个不断发生变化的外部API要容易接受的多，虽然这样做和我们协同开发、模块化开发的初衷是完全相悖的。</p>
<p>最后，我们为什么要修改API呢？为了API看起来更加漂亮？为了提供更多有趣的功能？还是仅仅我们觉得到了改变了时候了？对于用户来说，他们更愿意使用一个稳定但是看起来不那么时髦的API，而不是使用一个很时髦，但是会经常变动的API。在这个问题上，项目开发者是实用派。但这并不意味着我们不再改进API了，在后面，我会具体介绍如何能让API保持稳定的同时，让API持续改进。</p>
<h3>Quality of API</h3>
<p>在正式说兼容性之前，首先要明确一下，什么是好的API，因为导致API的不兼容的根源总是来自一个想法：“期望通过这次改变把API变得更好”。</p>
<p><strong>容易理解</strong><br />
如果一个API不能让大多数使用者快速学会，这一定不是一个好的API。 比如iOS的滑动解锁，老人和小孩都能都能一次解锁，而Nokia的经典两键解锁，你懂的。</p>
<p><strong>一致性</strong><br />
一致性能大大降低用户的学习和使用成本，用户过去的努力学习，能持续的收效。</p>
<p><strong>容易查找和学习</strong><br />
API必须要有文档，并且介绍清晰，提供尽可能多的示例和可copy－paste的代码，降低用户的使用门槛。</p>
<p><strong>提供简单的方案</strong><br />
API要能解决复杂的问题，提供很多可配置项，但是对于那些最常见的case，如果有一个简单的方案供给用户使用，这样能大大提高API的可用性</p>
<p><strong>保护用户在API上的已有工作</strong><br />
用户过去在调用API、基于API开发所做的工作，这样才能给用户带来价值的同时，不破坏他们过去的劳动成果。</p>
<h3>如何保证API的兼容</h3>
<h4>采用良好的设计思路</h4>
<p>在设计过程中，如果能按照下面的方式来进行设计，会让这个API生命更长久</p>
<ul>
<li>面向用例的设计，收集用户建议，把自己模拟成用户，保证API设计的易用和合理
<li>保证后续的需求可以通过扩展的形式完成
<li>第一版做尽量少的内容，由于新需求可以通过扩展的形式完成，因此尽量少做事情是抑制API设计错误的一个有效方案
<li>对外提供清晰的API和文档规范，避免用户错误的使用API，尤其是避免API（见第一节）靠后级别的API被用户知晓与误用
</ul>
<p>除此之外，下面还列出了一些具体的设计方法：</p>
<ul>
<li>方法优于属性
<li>工厂方法优于构造函数
<li>避免过多继承
<li>避免由于优化或者复用代码影响API
<li>面向接口编程
<li>扩展参数应当是便利的
<li>对组件进行合理定位，确定暴露多少接口
<li>提供扩展点
</ul>
<h4>有效的API评审</h4>
<p>API设计完成以后，需要经过周密的设计评审，评审的重点如下：</p>
<ul>
<li>用例驱动，评审前必须提供完善的使用用例，确保用例的合理性和完备性。
<li>一致性，是否与系统中其他模块的接口风格一致，是否与对称接口的设计一致。
<li>简单明了，API应该简单好理解，容易学习和使用的API才不容易被误用，给我们带来更多的麻烦。
<li>API尽可能少，如果一个API可以暴露也可以不暴露，那么就不要暴露他，等到用户真正有需求的时候再将它成为一个公开接口也不迟。
<li>支持持续改进，API是否能够方便地通过扩展的方式增加功能和优化。
</ul>
<h4>把握API的生命周期</h4>
<p>每一个API都是有生命周期的，我们需要让API的生命周期更长，并且在API的生命周期结束时能让其平滑的消亡。</p>
<ul>
<li>告诉用户我们是如何设计的，避免误用，提供指导，错误的使用往往是缩短API寿命的一大杀手
<li>提供试用期，API不可能一开始就是稳定，经过试用的API才能有更强的生命力
<li>为API分级：内部使用；二次开发使用；开发或试用中；稳定；弃用API。避免API被滥用的同时，我们可以通过调整API的级别，来扩大其影响力，也能更优雅的结束一个API的生命周期。
</ul>
<h4>保持API的逐步改善</h4>
<p>过去我们总希望能将现有的“不合理”的设计完全推翻，然后按照现在“美好”的思路，重新设计这个API，但是在一段时间以后，又会碰到一样的状况，需要再推翻一次。 如果我们没有有效的逐步改善的办法，依靠推翻现有设计，重新设计API只能让我们回到起点，然后重现之前的过程。 要有一套行之有效的持续改善的办法来在API兼容的同时，改善API使之更好。</p>
<h4>提高API的可测试性</h4>
<p>API需要是可测试的，测试不应依赖实现，测试充分的API，尤其是经过了严格的“兼容性整合测试”（见下文）的API，更能保证在升级的过程中不出现兼容性问题。</p>
<p>兼容性整合测试，是指一组测试用例集合，这组测试用例会站在使用者的立场上使用API。在API升级以后，再检测这组测试用例是否能完全符合预期的通过测试，尽可能的发现兼容性问题。</p>
<h4>避免极端的意见</h4>
<p>在设计API的时候，一定要避免任何极端的意见，尤其是以下几点：</p>
<ul>
<li>必须漂亮（API一定要漂亮吗？前文已经说过了）
<li>API必须被正确地使用（用户很难理解如何正确的使用API，API的设计者要充分考虑API被误用的情况：如果一个API可能会被误用，那么它一定会被误用）
<li>必须简单（我们总会面临复杂的需求，能两者兼顾的API是更好的API）
<li>必须高性能（性能可以通过其他手段优化，不应该影响API的设计）
<li>必须绝对兼容（尽管本文一直提到如何保证兼容，但是我们仍然要意识到，一些极少情况下会遇到的不兼容是可以容忍的）
</ul>
<h4>一些具体的实施方案</h4>
<p>在一个API不可避免要消亡或者改变的时候，我们应该接受并且面对这个事实，下面列举了几种保证兼容性的前提下，对API进行调整的办法：</p>
<ul>
<li>将API标记为弃用，重新建立一个新的API。如果一个API不可避免要被消亡，这是唯一的办法。
<li>为其添加额外的参数或者参数选项来实现功能添加
<li>将现有API拆成两部分，提供一个精简的核心API，过去的API通过封装核心API上实现。这通常用于解决用户需要一个代码精简的版本时。
<li>在现有的API基础上进行封装，提供一个功能更丰富的包或者类
</ul>
<h3>小结</h3>
<p>设计一个保持兼容的API是很困难的。在这之前，作者需要理解什么是API，以及如何评估API的质量以后，通过良好的设计思路以及改进方法，来保证API的向后兼容。</p>
<h3>其他</h3>
<p>事实上，Tangram base库自从1.3.4版本以后，就已经做到了API的向后兼容，如果对Tangram感兴趣，可以前往Tangram网站查阅。</p>
<p>如果你对Javascript 的API兼容有什么自己的见解，欢迎留言讨论。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.baiduux.com/blog/2011/06/21/javscript-api-compatible/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>百度与中科院,北航联合开展web前端前沿技术课程</title>
		<link>http://www.baiduux.com/blog/2011/06/17/fe-class/</link>
		<comments>http://www.baiduux.com/blog/2011/06/17/fe-class/#comments</comments>
		<pubDate>Fri, 17 Jun 2011 05:50:14 +0000</pubDate>
		<dc:creator>mbo</dc:creator>
				<category><![CDATA[web前端技术课程]]></category>

		<guid isPermaLink="false">http://www.baiduux.com/blog/?p=1056</guid>
		<description><![CDATA[随着互联网发展，前端展示、交互，以及性能和安全的要求越来越高，加上HTML5新技术和产品多终端需求，前端技术在产品中发挥的重要性更加凸显。百度web前端研发部精心准备为中科院研究生院以及北京航天航空大学的学生准备了 web前端前沿技术系列讲座课程。

课程从web前端发展趋势，到CSS样式表，JS语言等前端专业领域，再到前沿的HTML5&#38;CSS3，地图API，web安全，涵盖了几乎所有主流 web前端领域的知识体系。这是两所高校首次开设web前端领域课程。包括百度首席产品设计师孙云丰以及web前端研发部的高级工程师们在繁忙的工作压力 下还努力抽出时间编写教案和准备课程。当然，还有出卖色相。。。用海盗装吸引了众多学生的眼球！
在6月14日下午在中科院成功的进行了web前端前沿技术的第一堂课！吸引了250多名科苑学子报名参加。


（孙云丰在讲解搜索产品的发展）


（百度web前端研发部高级工程师李学健在讲解web前端发展过程）

（百度web前端研发部前端架构师黄方荣在讲解web前端技术总览）


]]></description>
			<content:encoded><![CDATA[<p>随着互联网发展，前端展示、交互，以及性能和安全的要求越来越高，加上HTML5新技术和产品多终端需求，前端技术在产品中发挥的重要性更加凸显。百度web前端研发部精心准备为中科院研究生院以及北京航天航空大学的学生准备了 web前端前沿技术系列讲座课程。</p>
<p><a href="http://www.baiduux.com/blog/wp-content/uploads/wp-get-url.php?filename=1330426377web前端课程海报.jpeg&amp;type=image%2Fjpeg&amp;width=380&amp;height=477"><img class="alignnone size-full wp-image-1377" title="web前端课程海报" src="http://www.baiduux.com/blog/wp-content/uploads/wp-get-url.php?filename=1330426377web前端课程海报.jpeg&amp;type=image%2Fjpeg&amp;width=380&amp;height=477" alt="" /></a></p>
<p>课程从web前端发展趋势，到CSS样式表，JS语言等前端专业领域，再到前沿的HTML5&amp;CSS3，地图API，web安全，涵盖了几乎所有主流 web前端领域的知识体系。这是两所高校首次开设web前端领域课程。包括百度首席产品设计师孙云丰以及web前端研发部的高级工程师们在繁忙的工作压力 下还努力抽出时间编写教案和准备课程。当然，还有出卖色相。。。用海盗装吸引了众多学生的眼球！</p>
<p>在6月14日下午在中科院成功的进行了web前端前沿技术的第一堂课！吸引了250多名科苑学子报名参加。</p>
<p><span id="more-1056"></span></p>
<p><a href="http://www.baiduux.com/blog/wp-content/uploads/wp-get-url.php?filename=1330426521孙云丰讲解搜索引擎发展.jpeg&amp;type=image%2Fjpeg&amp;width=450&amp;height=316"><img class="alignnone size-full wp-image-1381" title="孙云丰讲解搜索引擎发展" src="http://www.baiduux.com/blog/wp-content/uploads/wp-get-url.php?filename=1330426521孙云丰讲解搜索引擎发展.jpeg&amp;type=image%2Fjpeg&amp;width=450&amp;height=316" alt="" /></a></p>
<p>（孙云丰在讲解搜索产品的发展）</p>
<p><a href="http://www.baiduux.com/blog/wp-content/uploads/wp-get-url.php?filename=1330426485孙云丰讲解搜索引擎发展2.jpeg&amp;type=image%2Fjpeg&amp;width=288&amp;height=432"><img class="alignnone size-full wp-image-1380" title="孙云丰讲解搜索引擎发展2" src="http://www.baiduux.com/blog/wp-content/uploads/wp-get-url.php?filename=1330426485孙云丰讲解搜索引擎发展2.jpeg&amp;type=image%2Fjpeg&amp;width=288&amp;height=432" alt="" /></a></p>
<p><a href="http://www.baiduux.com/blog/wp-content/uploads/wp-get-url.php?filename=13304242814.jpeg&amp;type=image%2Fjpeg&amp;width=384&amp;height=267"><img class="alignnone size-full wp-image-1310" title="4" src="http://www.baiduux.com/blog/wp-content/uploads/wp-get-url.php?filename=13304242814.jpeg&amp;type=image%2Fjpeg&amp;width=384&amp;height=267" alt="" /></a></p>
<p>（百度web前端研发部高级工程师李学健在讲解web前端发展过程）</p>
<p><a href="http://www.baiduux.com/blog/wp-content/uploads/wp-get-url.php?filename=13304244235.jpeg&amp;type=image%2Fjpeg&amp;width=414&amp;height=316"><img class="alignnone size-full wp-image-1315" title="5" src="http://www.baiduux.com/blog/wp-content/uploads/wp-get-url.php?filename=13304244235.jpeg&amp;type=image%2Fjpeg&amp;width=414&amp;height=316" alt="" /></a></p>
<p>（百度web前端研发部前端架构师黄方荣在讲解web前端技术总览）</p>
<p><br class="spacer_" /></p>
<p><br class="spacer_" /></p>
]]></content:encoded>
			<wfw:commentRss>http://www.baiduux.com/blog/2011/06/17/fe-class/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>tangram开发中使用的开源工具介绍</title>
		<link>http://www.baiduux.com/blog/2011/04/15/tangram-dev-tools/</link>
		<comments>http://www.baiduux.com/blog/2011/04/15/tangram-dev-tools/#comments</comments>
		<pubDate>Fri, 15 Apr 2011 05:58:18 +0000</pubDate>
		<dc:creator>xyz</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[前端技术]]></category>
		<category><![CDATA[tangram]]></category>
		<category><![CDATA[开源]]></category>

		<guid isPermaLink="false">http://www.baiduux.com/blog/?p=1043</guid>
		<description><![CDATA[tangram是百度前端研发部推出的一个开源js库，在百度各产品线上广泛使用。在开发tangram项目时，tangram开发团队制定了一个开发流程，用来保证项目质量和进度。在这个流程中，我们使用了各种开源工具来辅助提高效率，取得了良好的效果。本文将简要介绍这些开源工具和使用体会，希望对提升你的开发效率和质量有所帮助。]]></description>
			<content:encoded><![CDATA[<p>tangram是百度前端研发部推出的一个开源js库，在百度各产品线上广泛使用。在开发tangram项目时，tangram开发团队制定了一个开发流程，用来保证项目质量和进度。在这个流程中，我们使用了各种开源工具来辅助提高效率，取得了良好的效果。本文将简要介绍这些开源工具和使用体会，希望对提升你的开发效率和质量有所帮助。<br />
<span id="more-1043"></span><br />
 目前tangram的整个开发流程如下:<br />
 &#8211; 编写代码和单元测试用例。用到的工具有firebug和qunit。<br />
 &#8211; gjslint检查代码。<br />
 &#8211; 提交代码code review，用到的工具有Rietveld。<br />
 &#8211; 根据code review 结果修改代码，重新进行gjslint代码检查和过所有单元测试用例，直到code review通过<br />
 &#8211; 提交代码到github。用到的工具有git。<br />
 &#8211; 发布新的版本。使用jsdoc-toolkit生成api文档，使用ant生成需要的js文件，使用yui compressor js/css压缩工具压缩源代码。<br />
 整个开发流程及其中使用到的工具如下图所示:</p>
<p><img src="http://tangram.baidu.com/img/tangram_flow.jpg" alt="" width="600" /></p>
<p><br class="spacer_" /></p>
<p>根据在开发流程中出现的顺序，对每个工具简要介绍如下：</p>
<p>- firebug : 几乎所有写html/css/js代码的人都熟悉的工具，tangram开发调试中用到。</p>
<p>官方站点 : <a href="http://getfirebug.com/">http://getfirebug.com/</a></p>
<p>- closure linter    (gjslint)  代码检查工具。Google开发的js代码检查工具，它能够检查代码风格，语法错误，还能够自动优化代码，功能十分强大。我们在开发完Tangram的代码后用它来检测代码风格以及语法错误，来保持代码风格统一和提高代码质量。</p>
<p>官方站点 : <a href="http://code.google.com/closure/utilities/docs/linter_howto.html">http://code.google.com/closure/utilities/docs/linter_howto.html</a></p>
<p>-  qunit  jquery 团队开发的js单元测试框架，和jquery一样简单好用。我们开发时采用该js框架写测试用例。而我们的测试团队将其集成到测试平台内，然后在远程虚拟机上搭建了各种操作系统和浏览器的环境。该测试平台每天都会在各种浏览器下运行当天提交的所有代码的测试用例，并通过邮件自动发送测试报告。</p>
<p>官方站点 : <a href="http://docs.jquery.com/QUnit">http://docs.jquery.com/QUnit</a></p>
<p>- Rietveld Code Review Tool  python 之父写的code review工具，通过它能很方便的进行多人code review 。Tangram在内部开发的每行代码都必须经过这个code review平台 review通过后才能提交到github。</p>
<p>官方站点 : <a href="http://code.google.com/p/rietveld/">http://code.google.com/p/rietveld/</a></p>
<p>-  jsdoc-toolkit   js版的javadoc，用于从源代码的注释生成文档。目前整个tangram.baidu.com的文档都是使用jsdoc-toolkit生成的。</p>
<p>官方站点 : <a href="http://code.google.com/p/jsdoc-toolkit/">http://code.google.com/p/jsdoc-toolkit/</a></p>
<p>- git git是linux之父 Linus Torvalds 开发的用于管理linux源代码的代码版本管理工具， 它具有分布式等特点，既能在单机上管理你写给自己用的小项目，也非常适合开发人员众多的大型项目。它方便的贡献代码机制更是为开源项目量身定制。tangram项目使用git进行版本管理，同时源代码也托管在github.com上。</p>
<p>官方站点 : <a href="http://git-scm.com/">http://git-scm.com/</a></p>
<p>- ant    apache基金会旗下项目，用来build代码。tangram每次发布新版本时提供下载的各种源代码都是通过该工具生成。在tangram的release目录下就可以看到对于该工具的配置。</p>
<p>官方站点 : <a href="http://ant.apache.org/">http://ant.apache.org/</a></p>
<p>- yui compressor js/css压缩工具，用于压缩js代码，减少下载消耗的带宽。tangram codesearch工具 以及发布的版本中包含的压缩代码都是该工具完成的。</p>
<p>官方站点 : <a href="http://developer.yahoo.com/yui/compressor/">http://developer.yahoo.com/yui/compressor/</a></p>
<p>当然还有另一个优秀的代码压缩工具 google closure compiler ,代码压缩率比yui 压缩工具要高</p>
<p>官方站点 : <a href="http://code.google.com/closure/compiler/">http://code.google.com/closure/compiler/</a></p>
<p>曼昆在《经济学原理》里面说，决定一个国家实力与人民生活水平高低的因素是这个国家的生产力水平。同样也可以说，决定一个软件公司实力与程序员工资高低的因素是该公司的代码生产力水平。tangram使用的这些开源工具大大的提高了我们的开发效率和开发水平，我们对它们的创造者们充满崇敬和感激。同样，让tangram成为对大家有用的开源工具，也是我们tangram开发团队的目标。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.baiduux.com/blog/2011/04/15/tangram-dev-tools/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>初探AIR for Android开发</title>
		<link>http://www.baiduux.com/blog/2011/04/06/air-for-android/</link>
		<comments>http://www.baiduux.com/blog/2011/04/06/air-for-android/#comments</comments>
		<pubDate>Wed, 06 Apr 2011 08:13:30 +0000</pubDate>
		<dc:creator>Leon</dc:creator>
				<category><![CDATA[Flash]]></category>

		<guid isPermaLink="false">http://www.baiduux.com/blog/?p=1003</guid>
		<description><![CDATA[Adobe发布mobile AIR已经有一段时间了，但是移动设备的UI与控件与PC端截然不同，导致真正使用AIR技术开发的移动设备程序少之又少，而前段时间，adobe终于发布了包括移动UI组件的Flex SDK &#8220;Hero&#8221; (就是以前的Slider)，虽然只支持Android系统，但是我们可以看到电子市场上使用AIR技术开发的程序越来越多。本文就将以MP3电台为例，介绍使用Flex Hero 开发mobile AIR应用程序的一些方法和心得。
介绍移动应用程序
移动程序界面中有一个重要的概念：屏幕，如下图


在MP3电台这个程序中，选台界面和播放界面就是两个“屏幕”，在PC端，这些操作是可以在一起进行的，可是由于移动设备屏幕大小的原因，无法塞在一个界面里。所以我们在选完台之后，整个屏幕都将转换为电台播放界面。
Flex Hero中的View
在Flex &#8220;Hero&#8221;里，“屏幕”的概念叫做View。hero中关于移动平台的核心类如下：

其中，MobileApplication相当于桌面版本的Application，是整个程序的容器。ViewNavigator管理各个View的显示与切换，也包含顶部控制栏ActionBar。

ViewNavigator处理视图切换的方法：
navigator.pushView&#40;view,data,transition=null&#41;; 
navigator.popView&#40;transition=null&#41;;
ViewNavigator.pushView方法用于转换到新的视图，例如，当用户在频道列表页面选择了一个频道时，我们可以执行
navigator.pushView&#40;RadioPlay,&#123;channel_item:channelList.selectedItem&#125;&#41;;
这样的话，就切换到了RadioPlay这个视图。
这时，如果用户按下了android上的后退按钮，则Flex框架会自动执行navigator.popView操作，这样会回到上一个视图。当然，我们也可以捕获这个键盘事件，然后执行自定义代码。
this.addEventListener&#40;KeyboardEvent.KEY_UP,function&#40;e:KeyboardEvent&#41;&#123;
&#160; &#160; if&#40;e.keyCode == Keyboard.BACK&#41;&#123;
&#160; &#160; &#160; &#160; e.stopPropagation&#40;&#41;;
&#160; &#160; &#160; &#160; //其他操作,例如存储数据等
&#160; &#160; &#160; &#160; //其他操作完毕
&#160; &#160; &#160; &#160; navigator.popView&#40;&#41;;
&#160; &#160; &#125; 
&#160;&#125;&#41;;
数据驱动的视图
视图切换时，Flex默认会把上一个视图的UI销毁（可以通过设置destructionPolicy=&#8221;none&#8221;来避免销毁），这样一来，我们回退到上一个视图的时候，就会丢失之前的UI状态，比如说频道列表的选中状态
View包含一个属性data，当开发者使用pushView方法时的第二个参数data将被赋值到这个属性中。而每次用户按下机身上的返回按钮，Flex框架执行popView方法自动恢复历史记录时，也会把上一次的data属性重新放到View的构造方法中。可以看出，如果我们需要在界面切换时保存当前视图的所有状态，相关代码如下：
this.addEventListener&#40;FlexEvent.VIEW_DEACTIVATE,saveState&#41;;
private function saveState&#40;event:Event&#41;:void&#123;
&#160; &#160; this.data.selection = channelList.selectedIndex;
&#160; &#160; this.data.scrollPosition = channelList.dataGroup.verticalScrollPosition;
&#125;
这样，我们在离开频道列表页的时候，就会把当前列表的选中状态记录下来，在重新显示这个View的时候，我们可以再恢复回来：
private function restoreState&#40;&#41;:void&#123;
&#160; &#160; if&#40;!data&#41;&#123;
&#160; &#160; &#160; &#160; data = new Object&#40;&#41;;
&#160; [...]]]></description>
			<content:encoded><![CDATA[<p>Adobe发布mobile AIR已经有一段时间了，但是移动设备的UI与控件与PC端截然不同，导致真正使用AIR技术开发的移动设备程序少之又少，而前段时间，adobe终于发布了包括移动UI组件的Flex SDK &#8220;Hero&#8221; (就是以前的Slider)，虽然只支持Android系统，但是我们可以看到电子市场上使用AIR技术开发的程序越来越多。本文就将以MP3电台为例，介绍使用Flex Hero 开发mobile AIR应用程序的一些方法和心得。</p>
<h2>介绍移动应用程序</h2>
<p>移动程序界面中有一个重要的概念：屏幕，如下图</p>
<p><img src="http://imgsrc.baidu.com/forum/mpic/item/a532bb2724051e408b82a18a.jpg" alt="屏幕示意" width="660" height="440" /></p>
<p><span id="more-1003"></span></p>
<p>在MP3电台这个程序中，选台界面和播放界面就是两个“屏幕”，在PC端，这些操作是可以在一起进行的，可是由于移动设备屏幕大小的原因，无法塞在一个界面里。所以我们在选完台之后，整个屏幕都将转换为电台播放界面。</p>
<h2>Flex Hero中的View</h2>
<p>在Flex &#8220;Hero&#8221;里，“屏幕”的概念叫做View。hero中关于移动平台的核心类如下：</p>
<p><img src="http://imgsrc.baidu.com/forum/mpic/item/56cac11871e1362ddbb4bd8a.jpg" alt="类示意图" width="420" height="230" /></p>
<p>其中，MobileApplication相当于桌面版本的Application，是整个程序的容器。ViewNavigator管理各个View的显示与切换，也包含顶部控制栏ActionBar。</p>
<p><img src="http://imgsrc.baidu.com/forum/mpic/item/e19311391acae973b9998f8a.jpg" alt="ViewNavigator解析" width="354" height="400" /></p>
<p>ViewNavigator处理视图切换的方法：</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">navigator.<span style="color: #660066;">pushView</span><span style="color: #009900;">&#40;</span>view<span style="color: #339933;">,</span>data<span style="color: #339933;">,</span>transition<span style="color: #339933;">=</span><span style="color: #003366; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <br />
navigator.<span style="color: #660066;">popView</span><span style="color: #009900;">&#40;</span>transition<span style="color: #339933;">=</span><span style="color: #003366; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<p>ViewNavigator.pushView方法用于转换到新的视图，例如，当用户在频道列表页面选择了一个频道时，我们可以执行</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">navigator.<span style="color: #660066;">pushView</span><span style="color: #009900;">&#40;</span>RadioPlay<span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span>channel_item<span style="color: #339933;">:</span>channelList.<span style="color: #660066;">selectedItem</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<p>这样的话，就切换到了RadioPlay这个视图。</p>
<p>这时，如果用户按下了android上的后退按钮，则Flex框架会自动执行navigator.popView操作，这样会回到上一个视图。当然，我们也可以捕获这个键盘事件，然后执行自定义代码。</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">addEventListener</span><span style="color: #009900;">&#40;</span>KeyboardEvent.<span style="color: #660066;">KEY_UP</span><span style="color: #339933;">,</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>e<span style="color: #339933;">:</span>KeyboardEvent<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span>e.<span style="color: #660066;">keyCode</span> <span style="color: #339933;">==</span> Keyboard.<span style="color: #000066;">BACK</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; e.<span style="color: #660066;">stopPropagation</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #006600; font-style: italic;">//其他操作,例如存储数据等</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #006600; font-style: italic;">//其他操作完毕</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; navigator.<span style="color: #660066;">popView</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span> <br />
&nbsp;<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<h2>数据驱动的视图</h2>
<p>视图切换时，Flex默认会把上一个视图的UI销毁（可以通过设置destructionPolicy=&#8221;none&#8221;来避免销毁），这样一来，我们回退到上一个视图的时候，就会丢失之前的UI状态，比如说频道列表的选中状态</p>
<p>View包含一个属性data，当开发者使用pushView方法时的第二个参数data将被赋值到这个属性中。而每次用户按下机身上的返回按钮，Flex框架执行popView方法自动恢复历史记录时，也会把上一次的data属性重新放到View的构造方法中。可以看出，如果我们需要在界面切换时保存当前视图的所有状态，相关代码如下：</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">addEventListener</span><span style="color: #009900;">&#40;</span>FlexEvent.<span style="color: #660066;">VIEW_DEACTIVATE</span><span style="color: #339933;">,</span>saveState<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #003366; font-weight: bold;">private</span> <span style="color: #003366; font-weight: bold;">function</span> saveState<span style="color: #009900;">&#40;</span>event<span style="color: #339933;">:</span>Event<span style="color: #009900;">&#41;</span><span style="color: #339933;">:</span><span style="color: #000066; font-weight: bold;">void</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">data</span>.<span style="color: #660066;">selection</span> <span style="color: #339933;">=</span> channelList.<span style="color: #660066;">selectedIndex</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">data</span>.<span style="color: #660066;">scrollPosition</span> <span style="color: #339933;">=</span> channelList.<span style="color: #660066;">dataGroup</span>.<span style="color: #660066;">verticalScrollPosition</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>这样，我们在离开频道列表页的时候，就会把当前列表的选中状态记录下来，在重新显示这个View的时候，我们可以再恢复回来：</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #003366; font-weight: bold;">private</span> <span style="color: #003366; font-weight: bold;">function</span> restoreState<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">:</span><span style="color: #000066; font-weight: bold;">void</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>data<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; data <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">new</span> Object<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span>data.<span style="color: #660066;">selection</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; channelList.<span style="color: #660066;">selectedIndex</span> <span style="color: #339933;">=</span> data.<span style="color: #660066;">selection</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span>data.<span style="color: #660066;">scrollPosition</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; channelList.<span style="color: #660066;">dataGroup</span>.<span style="color: #660066;">verticalScrollPosition</span> <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">data</span>.<span style="color: #660066;">scrollPosition</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<h2>优化技巧与注意事项</h2>
<p>Android上的AIR不会自动退出，也就是说，当用户按下home键或者后退到主屏幕时，AIR程序依然在运行。对于电台这样一个应用，后台运行是合乎情理的，但是如果想像传统程序一样，后退即退出的话，则需要额外做一些工作了：</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span>Capabilities.<span style="color: #660066;">cpuArchitecture</span><span style="color: #339933;">==</span><span style="color: #3366CC;">&quot;ARM&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; NativeApplication.<span style="color: #660066;">nativeApplication</span>.<span style="color: #660066;">addEventListener</span><span style="color: #009900;">&#40;</span>Event.<span style="color: #660066;">DEACTIVATE</span><span style="color: #339933;">,</span> handleDeactivate<span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">,</span> 0<span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <br />
<span style="color: #009900;">&#125;</span><br />
&nbsp;<br />
<span style="color: #003366; font-weight: bold;">private</span> <span style="color: #003366; font-weight: bold;">function</span> handleDeactivate<span style="color: #009900;">&#40;</span>event<span style="color: #339933;">:</span>Event<span style="color: #009900;">&#41;</span><span style="color: #339933;">:</span><span style="color: #000066; font-weight: bold;">void</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; NativeApplication.<span style="color: #660066;">nativeApplication</span>.<span style="color: #660066;">exit</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>AIR在一些设备上的动画运行效率比较低，我们可以给运动的元件设置cacheAsBitmapMatrix=true，将此元件交给GPU硬件渲染。这个属性和桌面版本的cacheAsBitmap的用法几乎完全一样，对于需要平移、缩放的显示对象，设置这个属性可以大大加快动画效率。</p>
<p>最后，MP3电台应用的源文件可以在<a href="http://cid-e37f9492ce02e8f5.office.live.com/self.aspx/.Public/attatchments/BaiduAirRadio.zip">这里</a>下载。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.baiduux.com/blog/2011/04/06/air-for-android/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

