<?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>谋智社区 &#187; 颠覆网络35天</title>
	<atom:link href="http://blog.mozilla.com/chinacommunity/archives/category/%e9%a2%a0%e8%a6%86%e7%bd%91%e7%bb%9c35%e5%a4%a9/feed" rel="self" type="application/rss+xml" />
	<link>http://blog.mozilla.com/chinacommunity</link>
	<description>火狐浏览器在中国</description>
	<lastBuildDate>Tue, 28 Dec 2010 08:18:30 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>颠覆网络35天 ─ TraceMonkey</title>
		<link>http://blog.mozilla.com/chinacommunity/archives/810</link>
		<comments>http://blog.mozilla.com/chinacommunity/archives/810#comments</comments>
		<pubDate>Thu, 20 Aug 2009 05:30:45 +0000</pubDate>
		<dc:creator>wzhao</dc:creator>
				<category><![CDATA[颠覆网络35天]]></category>

		<guid isPermaLink="false">http://blog.mozilla.com/chinacommunity/?p=810</guid>
		<description><![CDATA[这个系列的翻译停了好久，:( 其实是心有余力不足，呵呵。这几天看到Hacks不断出来非常棒的文章，所以还是尽量翻译一些，坚持这个系列。不过就不保证顺序了，呵呵──主要也是这篇讲述TraceMonkey的文章太棒，想先翻这一篇 原文地址：an overview of TraceMonkey 系列地址：颠覆网络35天 ==================================== 本文作者为David Mandelin，──Mozilla JavaScript团队工作人员。 Firefox 3.5拥有一个全新的JavaScript引擎，叫做TraceMonkey，在该引擎上跑JS应用要比Firefox 3快到3-4倍，从而为现有的网络应用加速。这篇文章大致的描述一下在TraceMonkey中包括的重要部件，以及他们是如何加速JavaScript 的。同样，在了解这些之后，你也就能知道什么样的网络应用通过TraceMonkey能够获得最大的提速，以及怎么样来写您的程序获得更大的性能提高。 为什么提速JS很难：动态类型 类似于JavaScript和Python这样的高级动态语言通常使得编程效率非常高，但是同类似Java或者C这样的静态语言相比，他们要慢一些。按照经验来说，一个JS程序通常要比同等的Java程序慢10倍。 像JS这样的动态语言比像Java或者C这样的静态语言慢主要有两个原因。第一个原因是在动态语言中，通常不太容易在执行之前知道值的类型信息。因此，语言本身必须使用一个通用的格式存储所有的值并且使用通用的操作来处理他们。 相反，在Java中，程序员声明变量和方法的类型，编译器可以在运行之前就知道这些值的类型。编译器可以使用特定的格式和操作来处理这些值，而这个过程要比通用的格式和操作快很多。下面，我会把这类操作叫做类型特定处理。 动态语言运行慢的第二个原因是，动态脚本语言通常实现为解释器，也就是由解释器执行；而静态语言通常被编译为原生代码。解释器可以很容易的构造，但 是他们需要额外的运行时间来处理跟踪他们的内部状态。像Java这样的语言会被编译成机器语言，基本上是不需要内部运行状态跟踪的。 让我们用一张图片来描述的更具体。这里有一个简单的加法的分解动作示意图，我们来计算一下：a + b，这里a和b均为整数。首先，我们忽略最右边的柱状图，集中在Firefox 3的JavaScript解释器和Java JIT执行效率的比较上。每个纵列都表示在某种语言上这个加法运算要做的分解动作。时间从上到下进行，每个不同颜色的盒子高度基本表示进行该分解动作需要的时间。 在中间，Java简单的运行一条机器指令：“加”命令，运行时间为T（一个处理器周期）。因为Java编译器预先知道运算值为标准的机器整数类型，她可以直接使用标准的整数加法机器指令。完了。 在左边，SpiderMonkey（FF3中的JS解释器）需要大概40个T。棕色部分的盒子部分为整个解释器的开销：解释器需要读取加操作，然后跳到解释器的通用加操作代码部分。橘色的盒子部分表示由于解释器不知道运算值的类型造成的额外工作。解释器需要解开a和b的通用描述格式，判断出他们的类型，选择特定的加法运算，把值转换为正确的类型，加法进行完之后，还需要把结果转换为通用的描述格式。 上面的图表显示，使用解释执行要比编译器慢一些，而使用不带任何类型信息的解释执行要慢很多。如果我们希望JS能够被运行的快一些，根据Amdahl定律，我们需要做点关于类型的事情。 通过跟踪获得类型 在TraceMonkey中，我们的目标是没有蛀牙，不对，我们的目标是编译出类型特定的代码。为了实现这个目标，TraceMonkey需要知道 变量的类型。但是JavaScript本身是没有类型的，而我们前面也说过JS引擎基本上是无法在运行前知道类型的，但是我们还要在运行之前编译出本地代 码，貌似无路可走了。 让我们换个角度来看这个问题。如果我们让程序在解释器中先跑一段，那么引擎就可以直接觉察到数值的类型了不是。然后，引擎可以使用这些类型来编译产生更快的类型特定的代码。最后，引擎就可以开始运行这些类型特定的代码，于是就运行的更快了～ 这个想法还有几个关键的细节。首先，当程序运行时，即便有很多的if语句和其他的程序分支，他始终在其中一个分支上。所以，引擎不太有机会觉察到方法中所有数值的类型──引擎通过路径来观察数值，我们称之为轨迹 Traces。因此，标准的编译器是对整个方法或者过程进行编译，而TraceMonkey是针对轨迹进行编译。运行期轨迹编译有个好处是在轨迹上的函数调用是内联inline的，这使得轨迹上的函数调用非常的快。 第二，编译类型特定的代码是占用运行时间的。如果一块代码仅仅会运行一次或少量的几次──这在网页代码中比较常见──他可能会占用更多的时间来编译和运行反而可能还不如直接在解释器里面运行来的快了。所以，他应该只去编译热代码（被运行很多次的代码）。在TraceMonkey中，我们通过跟踪循环来安排热代码。TraceMonkey开始在解释器中运行所有代码，并开始为循环记录轨迹中的热代码。 仅跟踪热循环代码结果之一就是：只运行几次的代码并不会在TraceMonkey中得到提速。而这通常不会影响实际运行效果，因为仅运行几次的代码通常很快就完事了，你可能都不会注意到他。另一个结果是那些不热的循环代码基本上不被运行，也不会被编译，从而节省编译时间。 最后，上面我们提到TraceMonkey是通过观察执行过程来判断数值类型，基本上算是事后诸葛亮的做法，可能并不能保证将来的结果──更准缺点 说算是事中诸葛亮：下次这部分代码被运行时，数值类型可能变了，或者第500次的时候开始变了也说不定。当我们已经产生好针对数字类型编译的代码之后，值 变成字符串类型了，那就糟糕了。所以，TraceMonkey必须在编译代码中加入类型检查。如果没有通过检查，TraceMonkey必须离开当前轨 迹，使用新类型重新编译这个轨迹上的代码。这就意味着拥有很多分支或者类型经常改变的代码在TraceMonkey中不一定能得到多少性能上的提高，因为 他需要花费运行时间来编译多出来的轨迹或者从这个轨迹跳到那个等等。 TraceMonkey操作起来～ 现在，我们通过一些示例来看一下TraceMonkey的实际操作情况：我们这里要完成的工作是把从1到N的整数都加到一个起始值上： function addTo(a, n) { for (var i = 0; i [...]]]></description>
			<content:encoded><![CDATA[<div>
<p>这个系列的翻译停了好久，:( 其实是心有余力不足，呵呵。这几天看到Hacks不断出来非常棒的文章，所以还是尽量翻译一些，坚持这个系列。不过就不保证顺序了，呵呵──主要也是这篇讲述TraceMonkey的文章太棒，想先翻这一篇</p>
<p>原文地址：<a href="http://hacks.mozilla.org/2009/07/tracemonkey-overview/">an overview of TraceMonkey</a><br />
系列地址：<a href="http://www.mijia.org/blog/?cat=166">颠覆网络35天</a></p>
<p>====================================</p>
<p><em>本文作者为<a href="http://blog.mozilla.com/dmandelin/">David Mandelin</a>，──Mozilla JavaScript团队工作人员。</em></p>
<p>Firefox 3.5拥有一个全新的JavaScript引擎，叫做TraceMonkey，在该引擎上跑JS应用要比Firefox 3快到3-4倍，从而为现有的网络应用加速。这篇文章大致的描述一下在TraceMonkey中包括的重要部件，以及他们是如何加速JavaScript 的。同样，在了解这些之后，你也就能知道什么样的网络应用通过TraceMonkey能够获得最大的提速，以及怎么样来写您的程序获得更大的性能提高。</p>
<p><strong>为什么提速JS很难：动态类型</strong></p>
<p>类似于JavaScript和Python这样的高级动态语言通常使得编程效率非常高，但是同类似Java或者C这样的静态语言相比，他们要慢一些。按照经验来说，一个JS程序通常要比同等的Java程序慢10倍。</p>
<p>像JS这样的动态语言比像Java或者C这样的静态语言慢主要有两个原因。第一个原因是在动态语言中，通常不太容易在执行之前知道值的类型信息。因此，语言本身必须使用一个通用的格式存储所有的值并且使用通用的操作来处理他们。</p>
<p>相反，在Java中，程序员声明变量和方法的类型，编译器可以在运行之前就知道这些值的类型。编译器可以使用特定的格式和操作来处理这些值，而这个过程要比通用的格式和操作快很多。下面，我会把这类操作叫做<strong>类型特定</strong>处理。</p>
<p>动态语言运行慢的第二个原因是，动态脚本语言通常实现为解释器，也就是由解释器执行；而静态语言通常被编译为原生代码。解释器可以很容易的构造，但 是他们需要额外的运行时间来处理跟踪他们的内部状态。像Java这样的语言会被编译成机器语言，基本上是不需要内部运行状态跟踪的。</p>
<p>让我们用一张图片来描述的更具体。这里有一个简单的加法的分解动作示意图，我们来计算一下：<code>a + b</code>，这里<code>a</code>和<code>b</code>均为整数。首先，我们忽略最右边的柱状图，集中在Firefox 3的JavaScript解释器和Java JIT执行效率的比较上。每个纵列都表示在某种语言上这个加法运算要做的分解动作。时间从上到下进行，每个不同颜色的盒子高度基本表示进行该分解动作需要的时间。</p>
<p><a href="http://hacks.mozilla.org/wp-content/uploads/2009/07/complexity.png" target="_blank"><img src="http://hacks.mozilla.org/wp-content/uploads/2009/07/complexity.png" alt="time diagram of add operation" width="500" /></a></p>
<p>在中间，Java简单的运行一条机器指令：“加”命令，运行时间为T（一个处理器周期）。因为Java编译器预先知道运算值为标准的机器整数类型，她可以直接使用标准的整数加法机器指令。完了。</p>
<p>在左边，SpiderMonkey（FF3中的JS解释器）需要大概40个T。棕色部分的盒子部分为整个解释器的开销：解释器需要读取加操作，然后跳到解释器的通用加操作代码部分。橘色的盒子部分表示由于解释器不知道运算值的类型造成的额外工作。解释器需要解开<code>a</code>和<code>b</code>的通用描述格式，判断出他们的类型，选择特定的加法运算，把值转换为正确的类型，加法进行完之后，还需要把结果转换为通用的描述格式。</p>
<p>上面的图表显示，使用解释执行要比编译器慢一些，而使用不带任何类型信息的解释执行要慢很多。如果我们希望JS能够被运行的快一些，根据<a href="http://en.wikipedia.org/wiki/Amdahl%27s_law">Amdahl定律</a>，我们需要做点关于类型的事情。</p>
<p><strong>通过跟踪获得类型</strong></p>
<p>在TraceMonkey中，我们的目标是没有蛀牙，不对，我们的目标是编译出类型特定的代码。为了实现这个目标，TraceMonkey需要知道 变量的类型。但是JavaScript本身是没有类型的，而我们前面也说过JS引擎基本上是无法在运行前知道类型的，但是我们还要在运行之前编译出本地代 码，貌似无路可走了。</p>
<p>让我们换个角度来看这个问题。如果我们让程序在解释器中先跑一段，那么引擎就可以直接<em>觉察</em>到数值的类型了不是。然后，引擎可以使用这些类型来编译产生更快的类型特定的代码。最后，引擎就可以开始运行这些类型特定的代码，于是就运行的更快了～</p>
<p>这个想法还有几个关键的细节。首先，当程序运行时，即便有很多的if语句和其他的程序分支，他始终在其中一个分支上。所以，引擎不太有机会觉察到方法中所有数值的类型──引擎通过路径来观察数值，我们称之为<em>轨迹 Traces</em>。因此，标准的编译器是对整个方法或者过程进行编译，而TraceMonkey是针对轨迹进行编译。运行期轨迹编译有个好处是在轨迹上的函数调用是内联inline的，这使得轨迹上的函数调用非常的快。</p>
<p>第二，编译类型特定的代码是占用运行时间的。如果一块代码仅仅会运行一次或少量的几次──这在网页代码中比较常见──他可能会占用更多的时间来编译和运行反而可能还不如直接在解释器里面运行来的快了。所以，他应该只去编译<em>热代码</em>（被运行很多次的代码）。在TraceMonkey中，我们通过跟踪循环来安排热代码。TraceMonkey开始在解释器中运行所有代码，并开始为循环记录轨迹中的热代码。</p>
<p>仅跟踪热循环代码结果之一就是：只运行几次的代码并不会在TraceMonkey中得到提速。而这通常不会影响实际运行效果，因为仅运行几次的代码通常很快就完事了，你可能都不会注意到他。另一个结果是那些不热的循环代码基本上不被运行，也不会被编译，从而节省编译时间。</p>
<p>最后，上面我们提到TraceMonkey是通过观察执行过程来判断数值类型，基本上算是事后诸葛亮的做法，可能并不能保证将来的结果──更准缺点 说算是事中诸葛亮：下次这部分代码被运行时，数值类型可能变了，或者第500次的时候开始变了也说不定。当我们已经产生好针对数字类型编译的代码之后，值 变成字符串类型了，那就糟糕了。所以，TraceMonkey必须在编译代码中加入类型检查。如果没有通过检查，TraceMonkey必须离开当前轨 迹，使用新类型重新编译这个轨迹上的代码。这就意味着拥有很多分支或者类型经常改变的代码在TraceMonkey中不一定能得到多少性能上的提高，因为 他需要花费运行时间来编译多出来的轨迹或者从这个轨迹跳到那个等等。</p>
<p><strong>TraceMonkey操作起来～</strong></p>
<p>现在，我们通过一些示例来看一下TraceMonkey的实际操作情况：我们这里要完成的工作是把从1到N的整数都加到一个起始值上：</p>
<pre style="font-family: monospace;"> <span style="color: #003366; font-weight: bold;">function</span> addTo<span style="color: #009900;">(</span>a<span style="color: #339933;">,</span> n<span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
   <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">(</span><span style="color: #003366; font-weight: bold;">var</span> i <span style="color: #339933;">=</span> <span style="color: #cc0000;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> n<span style="color: #339933;">;</span> <span style="color: #339933;">++</span>i<span style="color: #009900;">)</span>
     a <span style="color: #339933;">=</span> a <span style="color: #339933;">+</span> i<span style="color: #339933;">;</span>
   <span style="color: #000066; font-weight: bold;">return</span> a<span style="color: #339933;">;</span>
 <span style="color: #009900;">}</span>

 <span style="color: #003366; font-weight: bold;">var</span> t0 <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">new</span> Date<span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
 <span style="color: #003366; font-weight: bold;">var</span> n <span style="color: #339933;">=</span> addTo<span style="color: #009900;">(</span>0<span style="color: #339933;">,</span> 10000000<span style="color: #009900;">)</span><span style="color: #339933;">;</span>
 <span style="color: #000066;">print</span><span style="color: #009900;">(</span>n<span style="color: #009900;">)</span><span style="color: #339933;">;</span>
 <span style="color: #000066;">print</span><span style="color: #009900;">(</span><span style="color: #003366; font-weight: bold;">new</span> Date<span style="color: #009900;">(</span><span style="color: #009900;">)</span> <span style="color: #339933;">-</span> t0<span style="color: #009900;">)</span><span style="color: #339933;">;</span></pre>
<p>TraceMonkey总是先在<em>解释器</em>中运行。每当程序开始循环迭代的时候，TraceMonkey开始进入<em>监视</em>模式来为循环执行增加计数器。在FF3.5中，当计数器涨到2时，该循环就会被认为属于热代码，于是开始了轨迹跟踪。</p>
<p>这时TraceMonkey继续在解释器中执行，但是会开始在代码运行时<em>记录</em>轨迹。该轨迹就是运行到循环结束的代码，包括使用的类型信息。类型通过实际运行中的数值来确定。在我们的例子中，执行这段JS语句的循环最后变成我们的轨迹：</p>
<pre style="font-family: monospace;">    a <span style="color: #339933;">=</span> a <span style="color: #339933;">+</span> i<span style="color: #339933;">;</span>    <span style="color: #006600; font-style: italic;">// a is an integer number (0 before, 1 after)</span>
    <span style="color: #339933;">++</span>i<span style="color: #339933;">;</span>          <span style="color: #006600; font-style: italic;">// i is an integer number (1 before, 2 after)</span>
    <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">(</span><span style="color: #339933;">!</span><span style="color: #009900;">(</span>i <span style="color: #339933;">&lt;</span> n<span style="color: #009900;">)</span><span style="color: #009900;">)</span> <span style="color: #006600; font-style: italic;">// n is an integer number (10000000)</span>
      <span style="color: #000066; font-weight: bold;">break</span><span style="color: #339933;">;</span></pre>
<p>轨迹如果用JavaScript描述的话就是上面这个样子的。但是TraceMonkey需要更多的信息来编译该轨迹。真实的轨迹可能更像下面这个样子：</p>
<pre style="font-family: monospace;">  trace_1_start<span style="color: #339933;">:</span>
    <span style="color: #339933;">++</span>i<span style="color: #339933;">;</span>            <span style="color: #666666; font-style: italic;">// i is an integer number (0 before, 1 after)</span>
    temp <span style="color: #339933;">=</span> a <span style="color: #339933;">+</span> i<span style="color: #339933;">;</span>   <span style="color: #666666; font-style: italic;">// a is an integer number (1 before, 2 after)</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">(</span>lastOperationOverflowed<span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #009900;">)</span>
      exit_trace<span style="color: #009900;">(</span>OVERFLOWED<span style="color: #009900;">)</span><span style="color: #339933;">;</span>
    a <span style="color: #339933;">=</span> temp<span style="color: #339933;">;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">(</span><span style="color: #339933;">!</span><span style="color: #009900;">(</span>i <span style="color: #339933;">&lt;</span> n<span style="color: #009900;">)</span><span style="color: #009900;">)</span>   <span style="color: #666666; font-style: italic;">// n is an integer number (10000000)</span>
      exit_trace<span style="color: #009900;">(</span>BRANCHED<span style="color: #009900;">)</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">goto</span> trace_1_start<span style="color: #339933;">;</span></pre>
<p>这段轨迹描述了一个循环，也会被编译为一个循环，于是我们直接使用<code>goto</code>语句来描述这种结构。同样，整数加法可能会溢 出，需要额外的处理（例如，转换为浮点数加法来处理）从而跳出该轨迹。所以，轨迹必须包括溢出检查。最后，在到达最后的循环条件时，也要跳出轨迹。 exit代码告诉TraceMonkey从轨迹中跳出，TraceMonkey就可以决定之后执行什么样的操作，例如重新做加法（溢出了？）还是循环结束 了。需要注意的是，轨迹是使用特定的内部格式来记录的，不会报漏给程序员──上面的伪代码只是为了说明整个过程。</p>
<p>在记录之后，轨迹就可以被<em>编译</em>成类型特定的机器代码了。整个编译是由一个很小的JIT编译器（名字叫做<em>nanojit</em>）完成，结果被存储在内存中，准备好被CPU执行。</p>
<p>在解释器下一次进入循环头部时，TraceMonkey会开始<em>执行</em>编译好的轨迹。程序开始快速的执行。</p>
<p>在第65537次迭代中，整数加法将会溢出（2147450880 + 65537 = 2147516417，结果超过了2^31-1 = 2147483647，最大的32位整数。）在这个时候，TraceMonkey从轨迹中跳出并带有<code>OVERFLOWED</code>的 标记。TraceMonkey看到这个标记后，会返回到解释模式并重新做加法运算。因为解释器里面采用完全通用的方式来处理任何事情，溢出在这里会得到处 理并返回正常的结果。TraceMonkey会开始监控这个跳出点，如果溢出跳出点变成热点的话，一个全新的轨迹会从这里开始。</p>
<p>接下来，程序重新经过循环的开始。TraceMonkey会知道在这里他已经有一个编译好的轨迹，但是他也知道目前不能使用这个轨迹，因为该轨迹是针对整数编译的，在运算溢出之后，<code>a</code>被重新包装成浮点数类型。所以，TraceMonkey会记录一个全新的轨迹：</p>
<pre style="font-family: monospace;">  trace_2_start<span style="color: #339933;">:</span>
    <span style="color: #339933;">++</span>i<span style="color: #339933;">;</span>            <span style="color: #666666; font-style: italic;">// i is an integer number</span>
    a <span style="color: #339933;">=</span> a <span style="color: #339933;">+</span> i<span style="color: #339933;">;</span>      <span style="color: #666666; font-style: italic;">// a is a floating-point number</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">(</span><span style="color: #339933;">!</span><span style="color: #009900;">(</span>i <span style="color: #339933;">&lt;</span> n<span style="color: #009900;">)</span><span style="color: #009900;">)</span>   <span style="color: #666666; font-style: italic;">// n is an integer number (10000000)</span>
      exit_trace<span style="color: #009900;">(</span>BRANCHED<span style="color: #009900;">)</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">goto</span> trace_2_start<span style="color: #339933;">;</span></pre>
<p>TraceMonkey接下来会编译新的轨迹，在下一次循环迭代中，开始执行编译好的代码。这里，TraceMonkey保证JavaScript 以机器代码的方式被执行，即便类型发生变化。最后，轨迹结束并跳出，带有BRANCHED标记。在这个时候，TraceMonkey会再次回到解释器，解 释器重新接管直到程序结束。</p>
<p>下面是该程序在我笔记本上的运行时间记录（2.2GHz MacBook Pro）：</p>
<table border="0">
<tbody>
<tr>
<td>系统</td>
<td>运行时间（毫秒）</td>
</tr>
<tr>
<td>SpiderMonkey (FF3)</td>
<td>990</td>
</tr>
<tr>
<td>TraceMonkey (FF3.5)</td>
<td>45</td>
</tr>
<tr>
<td>Java (使用 int)</td>
<td>25</td>
</tr>
<tr>
<td>Java (使用 double)</td>
<td>74</td>
</tr>
<tr>
<td>C (使用 int)</td>
<td>5</td>
</tr>
<tr>
<td>C (使用 double)</td>
<td>15</td>
</tr>
</tbody>
</table>
<p>通过使用轨迹跟踪，上面的程序可以获得22倍的速度提升，而且基本上跟Java运行的一样快了！在循环中做简单数学运算的函数通常会通过轨迹跟踪获得很大的速度提升。很多位运算和数学原算，例如<code>bitops-3bit-bits-in-byte</code>，<code>ctrypto-sha1</code>和<code>math-spectral-norm</code>通常能够获得6-22倍的提速。</p>
<p>使用复杂运算的函数，例如对象操控，通常只会获得2-5倍的提速。这符合Amdahl定律：复杂运算需要更长时间。回过头来看看前面的图表，考虑更 为复杂的操作，比如需要在绿色实际执行区域内大概需要30个T的运行时间，橘色和棕色的区域还是30个T，这些都加起来，基本上也就是2倍速度的提升。 SunSpider benchmark中的<code>string-fasta</code>是属于这类的程序：大部分时间都会被花费在字符串操作上，绿色盒子部分的高度会比较大。</p>
<p>下面是我们的例子程序，你可以在浏览器中尝试一下：</p>
<p><script type="text/javascript">// <![CDATA[
function addTo(a, n) {
  for (var i = 0; i < n; ++i)
    a = a + i;
  return a;
}
var dts = 0;
var dtn = 0;
function runExample() {
  var t0 = new Date;
  var n = addTo(0, 10000000);
  var dt = new Date-t0;
  dts += dt;
  dtn += 1;
  var avg = Math.round(dts/dtn);
  document.getElementById('example_result').innerHTML = n + '';
  document.getElementById('example_time').innerHTML = dt + ' ms';
  document.getElementById('example_avg').innerHTML = avg + ' ms';
}
// ]]&gt;</script></p>
<div style="border: 1px solid black; margin: 12px; padding: 8px;"><button onclick="runExample()">运行示例</button>数值结果：<span id="example_result"> </span></p>
<p>运行时间：<span id="example_time"> </span></p>
<p>平均运行时间：<span id="example_avg"> </span></div>
<p><strong>理解和解决性能问题</strong></p>
<p>我们的目标是要让TraceMonkey更快更稳定，可以让您使用自己最想用的方式来书写程序，完全不用去担心性能。如果TraceMonkey并 没有提升你的程序运行速度，我们希望你能够提交个Bug给我们让我们来改进引擎。在这部分里，我们会介绍一些工具和技术来解决性能问题──假如您的程序连 2倍的提升都没有那基本上算是性能问题了。（当然您需要开启JIT编译选项，通过浏览器中打开<strong>about:config</strong>，然后把选项<strong>javascript.options.jit.content</strong>设定为<code>true</code>即为开启)。</p>
<p>第一步，需要正确的理解造成问题的原因。最普遍的原因是<em>轨迹中断</em>，意思是TraceMonkey无法完成记录一个轨迹，只好放弃 了。通常的结果是包含中断的循环重新在解释器中执行，所以你在循环中的性能并不会得到任何提高。有时候，在循环中某个路径被轨迹化了，但是在另外一条路径 上是中断的，这会使TraceMonkey在解释执行和执行本地代码之间来回切换。这可能会给你的提速打个折扣，或者根本没有提速，或者还拖慢了你的速 度：TraceMonkey在模式切换中会花费一些时间，所以快速切换会造成很糟糕的性能。</p>
<p>使用debug版本的浏览器或者使用JS shell程序（我自己<a href="https://developer.mozilla.org/en/Build_Documentation">做了</a>一个──我们不发布这一类构建版本），你可以让TraceMonkey把关于中断的信息打印出来。需要设定<code>TMFLAGS</code>环境变量，我经常像下面这样做：</p>
<pre>TMFLAGS=minimal,abort
dist/MinefieldDebug.app/Contents/MacOS/firefox</pre>
<p><code>minimal</code>选项表示打印出所有轨迹记录开始和成功结束的点。这可以给大家一个很直观的印象，究竟跟踪器在试图做什么。<code>abort</code>选项表示打印出所有被由于不支持结构体造成的中断发生点。（设定<code>TMFLAGS=help</code>会打印出其他支持的<code>TMFLAGS</code>选项然后退出。）</p>
<p>（需要注意<code>TMFLAGS</code>同样可以用来打印debug信息。如果您正在使用debug版本的FF3.5，环境变量需要设定为<code>TRACEMONKEY=abort</code>。）</p>
<p>下面这个例子就不会得到很多的提速：</p>
<p><script type="text/javascript">// <![CDATA[
function runExample2() {
  var t0 = new Date;
  var sum = 0;
  for (var i = 0; i < 100000; ++i) {
    sum += i;
  }
  var prod = 1;
  for (var i = 1; i < 100000; ++i) {
    eval("prod *= i");
  }
  var dt = new Date - t0;
  document.getElementById('example2_time').innerHTML = dt + ' ms';
}
// ]]&gt;</script></p>
<pre style="font-family: monospace;"><span style="color: #003366; font-weight: bold;">function</span> runExample2<span style="color: #009900;">(</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
  <span style="color: #003366; font-weight: bold;">var</span> t0 <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">new</span> Date<span style="color: #339933;">;</span>

  <span style="color: #003366; font-weight: bold;">var</span> sum <span style="color: #339933;">=</span> <span style="color: #cc0000;">0</span><span style="color: #339933;">;</span>
  <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">(</span><span style="color: #003366; font-weight: bold;">var</span> i <span style="color: #339933;">=</span> <span style="color: #cc0000;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> <span style="color: #cc0000;">100000</span><span style="color: #339933;">;</span> <span style="color: #339933;">++</span>i<span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
    sum <span style="color: #339933;">+=</span> i<span style="color: #339933;">;</span>
  <span style="color: #009900;">}</span>

  <span style="color: #003366; font-weight: bold;">var</span> prod <span style="color: #339933;">=</span> <span style="color: #cc0000;">1</span><span style="color: #339933;">;</span>
  <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">(</span><span style="color: #003366; font-weight: bold;">var</span> i <span style="color: #339933;">=</span> <span style="color: #cc0000;">1</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> <span style="color: #cc0000;">100000</span><span style="color: #339933;">;</span> <span style="color: #339933;">++</span>i<span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
    <span style="color: #000066; font-weight: bold;">eval</span><span style="color: #009900;">(</span><span style="color: #3366cc;">"prod *= i"</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">}</span>
  <span style="color: #003366; font-weight: bold;">var</span> dt <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">new</span> Date <span style="color: #339933;">-</span> t0<span style="color: #339933;">;</span>
  document.<span style="color: #660066;">getElementById</span><span style="color: #009900;">(</span>example2_time<span style="color: #3366cc;">‘).innerHTML = dt + ‘</span> ms<span style="color: #3366cc;">‘;
}</span></pre>
<div style="border: 1px solid black; margin: 12px; padding: 8px;"><button style="margin-right: 32px;" onclick="runExample2();">运行例子2</button><br />
运行时间：<span id="example2_time"> </span></div>
<p>如果我们设定<code>TMFLAGS=minimal,abort</code>，我们会得到下面的报告：</p>
<pre style="font-family: monospace;">Recording starting from ab.js:5@23
recording completed at  ab.js:5@23 via closeLoop

Recording starting from ab.js:5@23
recording completed at  ab.js:5@23 via closeLoop

Recording starting from ab.js:10@63
Abort recording of tree ab.js:10@63 at ab.js:11@70: eval.

Recording starting from ab.js:10@63
Abort recording of tree ab.js:10@63 at ab.js:11@70: eval.

Recording starting from ab.js:10@63
Abort recording of tree ab.js:10@63 at ab.js:11@70: eval.</pre>
<p>最开始的两对显示第一次循环，在第5行开始，被跟踪的很好。接下来的几行显示TraceMonkey开始在第10行跟踪循环，但是由于<code>eval</code>每次都失败了。</p>
<p>这个debug输出中包含一条很重要的信息，就是你会看到很多的消息在引用不断增加的<em>内部树状结构</em>等等。这些不是什么问题：他们通常表示在完成跟踪一个循环过程中的<em>延迟</em>时间，因为TraceMonkey在连接内部和外部的循环。事实上，如果继续看这些输入信息，您通常会看到循环到最后会开始进行跟踪。</p>
<p>否则，这些中断基本上都是由不支持的JavaScript结构造成的。针对像<code>+</code>这样的基本操作实现跟踪支持是很容易实现的。我们目前没有足够的事件去为每个最新的JavaScript特性提供可靠的安全的跟踪支持，所以像<code>参数</code>等比较高级的咚咚还无法在FF3.5中被跟踪。其他没有被支持的高级特性还包括getter和setter，with和eval。目前有部分对闭包的支持，不过要取决于他们是怎么被使用的。对程序进行重构避免使用这些结构可以帮助提升性能。</p>
<p>还有两个特别的JavaScript特性不支持被跟踪：</p>
<ul>
<li>递归。TraceMonkey不会把按照递归方式发生的迭代识别为循环，所以他不会尝试去跟踪他。重构代码，显示的使用<code>for</code>或者<code>while</code>可以提供更好的性能。</li>
<li>读取或者设置DOM属性。（DOM方法调用没有问题。）想避免这样的用法基本上是不可能的，但是把这部分代码重构为把DOM属性访问的代码移到热循环和性能非常重要的区域会好很多。</li>
</ul>
<p>我们现在正积极的争取实现上述特性的跟踪。例如，对<code>参数</code>的跟踪支持已经包含在Nightly构建版本中了。</p>
<p>下面的例子就重构为避免使用<code>eval</code>。当然，我可以更简单的使用内联方式做乘法。相反我使用了利用<code>eval</code>的函数，因为这是一个比较常用的方式来重构<code>eval</code>。注意<code>eval</code>还是不能被跟踪，但是他只运行一次所以没关系。</p>
<p><script type="text/javascript">// <![CDATA[
function runExample3() {
  var t0 = new Date;
  var sum = 0;
  for (var i = 0; i < 100000; ++i) {
    sum += i;
  }
  var prod = 1;
  var mul = eval("(function(i) { return prod * i; })");
  for (var i = 1; i < 100000; ++i) {
    prod = mul(i);
  }
  var dt = new Date - t0;
  document.getElementById('example3_time').innerHTML = dt + ' ms';
}
// ]]&gt;</script></p>
<pre style="font-family: monospace;"><span style="color: #003366; font-weight: bold;">function</span> runExample3<span style="color: #009900;">(</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
  <span style="color: #003366; font-weight: bold;">var</span> t0 <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">new</span> Date<span style="color: #339933;">;</span>

  <span style="color: #003366; font-weight: bold;">var</span> sum <span style="color: #339933;">=</span> <span style="color: #cc0000;">0</span><span style="color: #339933;">;</span>
  <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">(</span><span style="color: #003366; font-weight: bold;">var</span> i <span style="color: #339933;">=</span> <span style="color: #cc0000;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> <span style="color: #cc0000;">100000</span><span style="color: #339933;">;</span> <span style="color: #339933;">++</span>i<span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
    sum <span style="color: #339933;">+=</span> i<span style="color: #339933;">;</span>
  <span style="color: #009900;">}</span>

  <span style="color: #003366; font-weight: bold;">var</span> prod <span style="color: #339933;">=</span> <span style="color: #cc0000;">1</span><span style="color: #339933;">;</span>
  <span style="color: #003366; font-weight: bold;">var</span> mul <span style="color: #339933;">=</span> <span style="color: #000066; font-weight: bold;">eval</span><span style="color: #009900;">(</span><span style="color: #3366cc;">"(function(i) { return prod * i; })"</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>

  <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">(</span><span style="color: #003366; font-weight: bold;">var</span> i <span style="color: #339933;">=</span> <span style="color: #cc0000;">1</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> <span style="color: #cc0000;">100000</span><span style="color: #339933;">;</span> <span style="color: #339933;">++</span>i<span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
    prod <span style="color: #339933;">=</span> mul<span style="color: #009900;">(</span>i<span style="color: #009900;">)</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">}</span>
  <span style="color: #003366; font-weight: bold;">var</span> dt <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">new</span> Date <span style="color: #339933;">-</span> t0<span style="color: #339933;">;</span>
  document.<span style="color: #660066;">getElementById</span><span style="color: #009900;">(</span><span style="color: #3366cc;">‘example3_time’</span><span style="color: #009900;">)</span>.<span style="color: #660066;">innerHTML</span> <span style="color: #339933;">=</span> dt <span style="color: #339933;">+</span> <span style="color: #3366cc;">‘ ms’</span><span style="color: #339933;">;</span>
<span style="color: #009900;">}</span></pre>
<div style="border: 1px solid black; margin: 12px; padding: 8px;"><button style="margin-right: 32px;" onclick="runExample3();">运行例子3</button><br />
运行时间：<span id="example3_time"> </span></div>
<p>还有一些比较隐蔽的情况可能会影响到跟踪的性能。其中之一被称作<em>跟踪爆炸</em>，当在循环中有很多路径时可能会发生。假设一个循环中连着有10条<code>if</code>语 句：那整个循环体有1024条路径，可能会产生1024条轨迹要被记录。这会使用大量的内存，所以TraceMonkey会为每个循环最多记录32条轨 迹。如果循环中少于32条热轨迹，他会表现的很好。但是如果每个路径按照相同的概率发生，那么仅有3%的路径会被跟踪，性能会大打折扣。</p>
<p>这类问题可以使用<a href="https://developer.mozilla.org/en/TraceVis"><strong>TraceVis</strong></a>来分析，他可以生成TraceMonkey性能的可视化效果。目前，构建系统仅支持为Shell版本开启TraceVis，但是基本的系统还可以运行在浏览器中，目前也有<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=497999">正在进行的工作</a>致力于在浏览器中更方便的开启TraceVis。</p>
<p><a href="http://blog.mozilla.com/dmandelin/2009/02/26/tracevis-performance-visualization-for-tracemonkey/">这里有篇讨论TraceVis的文章</a>可能是目前对TraceVis最全面的解释，包括图表中各种标识的含义以及如何分析性能问题等。这篇文章同样包括一个详细的分析可以帮助更好的理解TraceMonkey的工作远离。</p>
<p><strong>同类比较</strong></p>
<p>下面我们来简单的同其他JavaScript JIT设计进行一下比较。我可能更多是假设性的比较，因为我不是很了解他们的细节──只是阅读过一些发布信息大致看过几眼代码。</p>
<p>有一个设计备选可能被叫做<em>per-method non-specializing JIT</em>，意思是一个JIT编译器在运行期编 译方法并产生通用的代码，跟解释器做的事情是一样的。因此，我们上面图标中的褐色部分就可以被去掉了。这一类JIT不需要花费时间来记录和编译轨迹，但是 他也没有做类型特化的工作，所以，橘色的盒子部分还是要有的。这样的引擎可以通过巧妙的设计橘色盒子部分并对其调优，同样可以拥有很惊人的性能提升。但是 由于橘色部分完全不能被去掉，所以数值程序最大的性能肯定不会优于类型特定的引擎。</p>
<p>在写这篇文章的时候，Nitro和V8都是轻量的非类型特化的JIT。（据说，V8会通过查看源代码试图猜测很少的几类类型信息，例如猜测在代码<code>a &gt;&gt; 2</code>中，<code>a</code>可能是个整数，从而来做部分类型特定操作。）这样看来，TraceMonkey在数值部分的表现应该更快一些。但是TraceMonkey会受一些使用对象的benchmark影响，因为我们的对象操作和内存管理还没有很好的被优化。</p>
<p>基础JIT一个更远的方案被叫做<em>per-method type-specializing JIT</em>。这一类JIT会根据方法调 用中的参数类型来尝试类型特化该方法。同TraceMonkey类似，这需要运行期观察：在方法每次被调用时，需要检查参数的类型，如果之前没有见过这些 类型，编译一个全新版本的方法。同样根TraceMonkey类似，这个设计可以很大程度上特化代码，并去掉上面图标中的褐色和橘色盒子部分。</p>
<p>我目前还不知道有谁在为JavaScript开发这类per-method type-specializing JIT，但是如果有人在做的话，我不会吃惊的。</p>
<p>per-method type-specializing JIT同跟踪JIT相比较，一个很大的缺点是基本的per-method JIT仅仅直接观察方法的输入参数。他必须利用算法推导出方法内部变量的类型信息，这一点很难，尤其是如果方法读取对象属性的话。因此，可能会有per- method type-specializing JIT在方法局部使用一些通用操作来完成。per-method设计的好处主要是方法仅需要为输入类型编译一套就好了，所以他不会有跟踪爆炸这样的问题。 而且，我认为per-method JIT在处理包含很多路径的方法上性能更好，而跟踪JIT在处理类型非常分明的方法上更快，尤其是方法从对象属性中读取了很多值时。</p>
<p><strong>结论</strong></p>
<p>希望到这里您能够对如何加速JavaScript引擎，TraceMonkey怎么个工作原理，以及如何分析和解决在TraceMonkey上运行 JavaScript时可能有的性能问题都有个基本的了解。如果您遇到任何性能问题，请帮忙报个Bug。Bug报告能够帮助我们不断的去调整引擎的性能。 最后，我们不断的改进，如果您非常愿意尝鲜的话，不妨使用Nightly构建的TraceMonkey。</p></div>
]]></content:encoded>
			<wfw:commentRss>http://blog.mozilla.com/chinacommunity/archives/810/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>颠覆网络35天 ─ 文字阴影聚光灯</title>
		<link>http://blog.mozilla.com/chinacommunity/archives/805</link>
		<comments>http://blog.mozilla.com/chinacommunity/archives/805#comments</comments>
		<pubDate>Wed, 19 Aug 2009 05:59:32 +0000</pubDate>
		<dc:creator>wzhao</dc:creator>
				<category><![CDATA[颠覆网络35天]]></category>

		<guid isPermaLink="false">http://blog.mozilla.com/chinacommunity/?p=805</guid>
		<description><![CDATA[原文地址：the text-shadow spotlight 系列地址：颠覆网络35天 ==================================== Zachary Johnson制作了另一个很炫的演示 has put together another fun demo。他使用JavaScript和text-shadow属性制作了一个聚光灯效果。已经被嵌入到下面了。如果看不到的话，查看他的博客文章。 使用Firefox 3.5观看演示]]></description>
			<content:encoded><![CDATA[<div>
<p>原文地址：<a href="http://hacks.mozilla.org/2009/06/text-shadow-spotlight/">the text-shadow spotlight</a><br />
系列地址：<a href="http://www.mijia.org/blog/?cat=166">颠覆网络35天</a></p>
<p>====================================</p>
<p><a href="http://www.zachstronaut.com/posts/2009/06/22/css-text-shadow-lighting-demo.html">Zachary Johnson制作了另一个很炫的演示 has put together another fun demo</a>。他使用JavaScript和<code><a href="http://www.mijia.org/blog/?p=200">text-shadow</a></code>属性制作了一个聚光灯效果。已经被嵌入到下面了。如果看不到的话，<a href="http://www.zachstronaut.com/posts/2009/06/22/css-text-shadow-lighting-demo.html">查看他的博客文章</a>。</p>
<div style="font-size: 120%;"><a href="http://www.zachstronaut.com/posts/2009/06/22/css-text-shadow-lighting-demo.html" target="_blank">使用Firefox 3.5观看演示</a></div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.mozilla.com/chinacommunity/archives/805/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>颠覆网络35天 ─ 使用localStorage保存数据</title>
		<link>http://blog.mozilla.com/chinacommunity/archives/795</link>
		<comments>http://blog.mozilla.com/chinacommunity/archives/795#comments</comments>
		<pubDate>Fri, 14 Aug 2009 04:32:15 +0000</pubDate>
		<dc:creator>wzhao</dc:creator>
				<category><![CDATA[颠覆网络35天]]></category>

		<guid isPermaLink="false">http://blog.mozilla.com/chinacommunity/?p=795</guid>
		<description><![CDATA[原文地址：saving data with localStorage 系列地址：颠覆网络35天 ==================================== 本文作者为Jeff Balogh。Jeff就职于Mozilla的互联网开发团队。 localStorage是Web Storage互联网存储规范中的一部分，现在在Firefox 3.5中得到支持。localStorage提供了简单的 provides a simple Javascript API，用来在浏览器中持久化key-value键值对。应该注意的是不要同SQL数据库存储提案混淆，后者是另外单独的（同时也是有争议的） 互联网存储规范的一部分。键值对可以存储在cookie中，不过你一定不想这么做。Cookie在每次请求中都会被发送到服务器端，如果使用大数据集合的 话会有性能问题，同样也在传输中会有安全问题，而且也许你不得不为了处理这些数据特别写大量代码，例如把cookie像数据库那么使唤。 这里有一个简单演示，可以把textarea中的内容存储到localStorage。你可以改变文字，打开新标签页，可以看到更新过的内容。或者重启浏览器，你的文字还会在那里。 // 使用localStorage最简单的方式就是像一个正常对象那样的使唤他： &#62;&#62;&#62; localStorage.foo = ‘bar’ &#62;&#62;&#62; localStorage.foo “bar” &#62;&#62;&#62; localStorage.length 1 &#62;&#62;&#62; localStorage[0] “foo” &#62;&#62;&#62; localStorage[‘foo’] “bar” &#62;&#62;&#62; delete localStorage[‘foo’] &#62;&#62;&#62; localStorage.length 0 &#62;&#62;&#62; localStorage.not_set null 如果喜欢使用函数的话，我们也有类似的API： &#62;&#62;&#62; localStorage.clear() &#62;&#62;&#62; localStorage.setItem(‘foo’, ‘bar’) &#62;&#62;&#62; localStorage.getItem(‘foo’) “bar” [...]]]></description>
			<content:encoded><![CDATA[<div>
<p>原文地址：<a href="http://hacks.mozilla.org/2009/06/localstorage/">saving data with localStorage</a><br />
系列地址：<a href="http://www.mijia.org/blog/?cat=166">颠覆网络35天</a></p>
<p>====================================</p>
<p><em>本文作者为<a href="http://blog.jeffbalogh.org/">Jeff Balogh</a>。Jeff就职于Mozilla的<a href="http://blog.mozilla.com/webdev/">互联网开发团队</a>。</em></p>
<p><a href="https://developer.mozilla.org/en/DOM/Storage#localStorage"><code>localStorage</code></a>是<a href="http://www.w3.org/TR/webstorage/#the-storage-interface">Web Storage</a>互联网存储规范中的一部分，现在在Firefox 3.5中得到支持。<code>localStorage</code>提供了简单的 provides a simple Javascript <abbr title="Application Programming Interface">API</abbr>，用来在浏览器中持久化key-value键值对。应该注意的是不要同<a href="http://www.w3.org/TR/webstorage/#sql">SQL数据库存储</a>提案混淆，后者是另外单独的（<a href="http://blog.vlad1.com/2009/04/06/html5-web-storage-and-sql/">同时也是有争议的</a>） 互联网存储规范的一部分。键值对可以存储在cookie中，不过你一定不想这么做。Cookie在每次请求中都会被发送到服务器端，如果使用大数据集合的 话会有性能问题，同样也在传输中会有安全问题，而且也许你不得不为了处理这些数据特别写大量代码，例如把cookie像数据库那么使唤。</p>
<p>这里有一个简单演示，可以把<code>textarea</code>中的内容存储到<code>localStorage</code>。你可以改变文字，打开新标签页，可以看到更新过的内容。或者重启浏览器，你的文字还会在那里。</p>
<p><textarea id="persisted-text" cols="50" rows="5"></textarea><br />
<script type="text/javascript">// <![CDATA[
  var supported = '这些文字已经被存储到本地──永久的。',
      unsupported = '噢，不，您的浏览器不支持localStorage。';
  if (window.localStorage) {
      var p = document.querySelector('#persisted-text');
      if (localStorage.text == null) {
          localStorage.text = p.value = supported;
      } else {
          p.value = localStorage.text;
      }
      p.addEventListener('keyup', function(){ localStorage.text = p.value; }, false);
  } else {
      document.getElementById('persisted-text').value = unsupported;
  }
// ]]&gt;</script></p>
<p>使用<code>localStorage</code>最简单的方式就是像一个正常对象那样的使唤他：</p>
<pre style="font-family: monospace;"><span style="color: #339933;">&gt;&gt;&gt;</span> localStorage.<span style="color: #660066;">foo</span> <span style="color: #339933;">=</span> <span style="color: #3366cc;">‘bar’</span>
<span style="color: #339933;">&gt;&gt;&gt;</span> localStorage.<span style="color: #660066;">foo</span>
<span style="color: #3366cc;">“bar”</span>
<span style="color: #339933;">&gt;&gt;&gt;</span> localStorage.<span style="color: #660066;">length</span>
<span style="color: #cc0000;">1</span>
<span style="color: #339933;">&gt;&gt;&gt;</span> localStorage<span style="color: #009900;">[</span><span style="color: #cc0000;">0</span><span style="color: #009900;">]</span>
<span style="color: #3366cc;">“foo”</span>
<span style="color: #339933;">&gt;&gt;&gt;</span> localStorage<span style="color: #009900;">[</span><span style="color: #3366cc;">‘foo’</span><span style="color: #009900;">]</span>
<span style="color: #3366cc;">“bar”</span>
<span style="color: #339933;">&gt;&gt;&gt;</span> <span style="color: #000066; font-weight: bold;">delete</span> localStorage<span style="color: #009900;">[</span><span style="color: #3366cc;">‘foo’</span><span style="color: #009900;">]</span>
<span style="color: #339933;">&gt;&gt;&gt;</span> localStorage.<span style="color: #660066;">length</span>
0
<span style="color: #339933;">&gt;&gt;&gt;</span> localStorage.<span style="color: #660066;">not_set</span>
<span style="color: #003366; font-weight: bold;">null</span></pre>
<p>如果喜欢使用函数的话，我们也有类似的API：</p>
<pre style="font-family: monospace;"><span style="color: #339933;">&gt;&gt;&gt;</span> localStorage.<span style="color: #660066;">clear</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span>
<span style="color: #339933;">&gt;&gt;&gt;</span> localStorage.<span style="color: #660066;">setItem</span><span style="color: #009900;">(</span><span style="color: #3366cc;">‘foo’</span><span style="color: #339933;">,</span> <span style="color: #3366cc;">‘bar’</span><span style="color: #009900;">)</span>
<span style="color: #339933;">&gt;&gt;&gt;</span> localStorage.<span style="color: #660066;">getItem</span><span style="color: #009900;">(</span><span style="color: #3366cc;">‘foo’</span><span style="color: #009900;">)</span>
<span style="color: #3366cc;">“bar”</span>
<span style="color: #339933;">&gt;&gt;&gt;</span> localStorage.<span style="color: #660066;">key</span><span style="color: #009900;">(</span><span style="color: #cc0000;">0</span><span style="color: #009900;">)</span>
<span style="color: #3366cc;">“foo”</span>
<span style="color: #339933;">&gt;&gt;&gt;</span> localStorage.<span style="color: #660066;">removeItem</span><span style="color: #009900;">(</span><span style="color: #3366cc;">‘foo’</span><span style="color: #009900;">)</span>
<span style="color: #339933;">&gt;&gt;&gt;</span> localStorage.<span style="color: #660066;">length</span>
<span style="color: #cc0000;">0</span></pre>
<p>如果你希望有个<code>localStorage</code>数据库可以对应当前会话，你可以使用<code>sessionStorage</code>。他提供同<code>localStorage</code>一样的接口，但是<code>sessionStorage</code>的生命周期被限制在当前浏览器窗口。你可以在同一个浏览器窗口中点击链接浏览，<code>sessionStorage</code>一直会被保存（去不同的网站也可以），一旦该浏览器窗口被关闭，数据库就会被删除了。<code>localStorage</code>针对长期存储，像w3c中描述的，浏览器应该把这类数据当作是“潜在的用户关键”数据。</p>
<p>不过当我发现<code>localStorage</code>仅仅支持保存字符串时未免有些伤心，我希望能够保存一些结构化的数据。我们可以借助Firefox 3.5中<a href="https://developer.mozilla.org/En/Using_native_JSON">原生的JSON</a>支持，可以非常容易的利用<code>localStorage</code>保存结构化对象数据：</p>
<pre style="font-family: monospace;">Storage.<span style="color: #660066;">prototype</span>.<span style="color: #660066;">setObject</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">(</span>key<span style="color: #339933;">,</span> value<span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
    <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">setItem</span><span style="color: #009900;">(</span>key<span style="color: #339933;">,</span> JSON.<span style="color: #660066;">stringify</span><span style="color: #009900;">(</span>value<span style="color: #009900;">)</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
<span style="color: #009900;">}</span>

Storage.<span style="color: #660066;">prototype</span>.<span style="color: #660066;">getObject</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">(</span>key<span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
    <span style="color: #000066; font-weight: bold;">return</span> JSON.<span style="color: #660066;">parse</span><span style="color: #009900;">(</span><span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">getItem</span><span style="color: #009900;">(</span>key<span style="color: #009900;">)</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
<span style="color: #009900;">}</span></pre>
<p><code>localStorage</code>数据库作用域限定于<a href="http://www.w3.org/TR/html5/browsers.html#origin-0">HTML5源定义</a>，基本上就是三元组<code>(scheme, host, port)</code>。换句话说，本地存储数据库在同样域名下的网页间是共享的，即便是在多个浏览器标签页中。不过，使用<code>http://</code>连接的页面是看不到使用<code>https://</code>连接会话中的数据库的。</p>
<p><code>localStorage</code> 和 <code>sessionStorage</code>都在Firefox 3.5、Safari 4和IE8中得到支持。你可以在<a href="http://www.quirksmode.org/dom/html5.html#localstorage">quirksmode.org</a>找到更详细的兼容性信息，尤其是在<a href="http://www.quirksmode.org/blog/archives/2009/06/html5_storage_t.html">保存事件</a>的一节中。</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.mozilla.com/chinacommunity/archives/795/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>颠覆网络35天 ─ 使用SVG和APNG制作动画纹理映射</title>
		<link>http://blog.mozilla.com/chinacommunity/archives/791</link>
		<comments>http://blog.mozilla.com/chinacommunity/archives/791#comments</comments>
		<pubDate>Thu, 13 Aug 2009 05:24:27 +0000</pubDate>
		<dc:creator>wzhao</dc:creator>
				<category><![CDATA[颠覆网络35天]]></category>

		<guid isPermaLink="false">http://blog.mozilla.com/chinacommunity/?p=791</guid>
		<description><![CDATA[原文地址：using SVG and APNG to create an animated texture map 系列地址：颠覆网络35天 ==================================== 昨天我们介绍了使用SVG来映射3D数据的演示。今天我们再介绍一个Hans的演示：在浏览器中动态为动画添加纹理效果。 他使用了同之前文章中一样的技术，但是这次加载了一个动画PNG图片然后在图片上映射一个随机的图片纹理，这里使用了他的SVG 投影技术。结果非常赞！查看演示： 在Firefox 3.5中查看演示]]></description>
			<content:encoded><![CDATA[<div>
<p>原文地址：<a href="http://hacks.mozilla.org/2009/06/svg-apng-animated-texture/">using SVG and APNG to create an animated texture map</a><br />
系列地址：<a href="http://www.mijia.org/blog/?cat=166">颠覆网络35天</a></p>
<p>====================================</p>
<p>昨天我们介绍了<a href="http://hacks.mozilla.org/2009/06/svg-filter-3d-data/">使用SVG来映射3D数据</a>的演示。今天我们再介绍一个Hans的演示：<a href="http://www.tapper-ware.net/stable/web.filter.apng.dynamicTexture/index.xhtml">在浏览器中动态为动画添加纹理效果</a>。</p>
<p>他使用了同之前文章中一样的技术，但是这次加载了一个动画PNG图片然后在图片上映射一个随机的图片纹理，这里使用了他的<a href="http://www.tapper-ware.net/2009/05/perspective-texture-with-6-lines-of-svg.html">SVG 投影技术</a>。结果非常赞！查看演示：</p>
<div style="font-size: 120%;"><a href="http://www.tapper-ware.net/stable/web.filter.apng.dynamicTexture/index.xhtml" target="_blank">在Firefox 3.5中查看演示<br />
<img src="http://www.tapper-ware.net/stable/web.filter.apng.dynamicTexture/texture.marshmallow.png" alt="" /></a></div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.mozilla.com/chinacommunity/archives/791/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>颠覆网络35天 ─ nth-* Firefox 3.5中全新的CSS属性</title>
		<link>http://blog.mozilla.com/chinacommunity/archives/776</link>
		<comments>http://blog.mozilla.com/chinacommunity/archives/776#comments</comments>
		<pubDate>Wed, 12 Aug 2009 04:58:47 +0000</pubDate>
		<dc:creator>wzhao</dc:creator>
				<category><![CDATA[颠覆网络35天]]></category>

		<guid isPermaLink="false">http://blog.mozilla.com/chinacommunity/?p=776</guid>
		<description><![CDATA[原文地址：new CSS3 properties in Firefox 3.5 &#8211; nth-* 系列地址：颠覆网络35天 ==================================== Firefox 3.5支持一些全新的CSS3选取器。在这篇文章中，我们会介绍其中的四个：:nth-child，:nth-last-child，:nth-of-type 和 :nth-last-of-type。 这些选取器也被称作伪类，可以为已有的选取器增加风格。我们来看一些实际的例子。 :nth-child 这个伪类允许为一组元素添加风格。最常见的例子就是在表格中隔行高亮数据单元格： tr:nth-child(even) { background-color: #E8E8E8; } 实际的例子（需要Firefox 3.5）： Row 1 Row 2 Row 3 Row 4 还可以使用特殊的标记来为超过两组元素添加风格。文档中对规则的描述不太准确，但是在例子中的“3”把元素分为三组，“+1”则是在组中的偏移量。在规范中还有很多例子。 tr:nth-child(3n+1) { background-color: red; } tr:nth-child(3n+2) { background-color: green; } tr:nth-child(3n+3) { background-color: blue; } 实际的例子（需要Firefox 3.5）： Row 1 Row 2 Row [...]]]></description>
			<content:encoded><![CDATA[<div>
<p>原文地址：<a href="http://hacks.mozilla.org/2009/06/css3-nth/">new CSS3 properties in Firefox 3.5 &#8211; nth-*</a><br />
系列地址：<a href="http://www.mijia.org/blog/?cat=166">颠覆网络35天</a></p>
<p>====================================</p>
<p>Firefox 3.5支持一些全新的CSS3选取器。在这篇文章中，我们会介绍其中的四个：<a href="https://developer.mozilla.org/en/CSS/%3anth-child">:nth-child</a>，<a href="https://developer.mozilla.org/en/CSS/%3anth-last-child">:nth-last-child</a>，<a href="https://developer.mozilla.org/en/CSS/%3anth-of-type">:nth-of-type</a> 和 <a href="https://developer.mozilla.org/en/CSS/%3anth-last-of-type">:nth-last-of-type</a>。</p>
<p>这些选取器也被称作<a href="https://developer.mozilla.org/en/css_reference#Selectors">伪类</a>，可以为已有的选取器增加风格。我们来看一些实际的例子。</p>
<p><strong><a href="https://developer.mozilla.org/en/CSS/%3anth-child">:nth-child</a></strong></p>
<p>这个伪类允许为一组元素添加风格。最常见的例子就是在表格中隔行高亮数据单元格：</p>
<pre style="font-family: monospace;">tr<span style="color: #3333ff;">:nth-</span>child<span style="color: #00aa00;">(</span>even<span style="color: #00aa00;">)</span>
<span style="color: #00aa00;">{</span>
    <span style="color: #000000; font-weight: bold;">background-color</span><span style="color: #00aa00;">:</span> <span style="color: #cc00cc;">#E8E8E8</span><span style="color: #00aa00;">;</span>
<span style="color: #00aa00;">}</span></pre>
<p>实际的例子（需要Firefox 3.5）：</p>
<p><!-- #ex1 tr:nth-child(even) { background-color: #E8E8E8; } --></p>
<table id="ex1" border="0">
<tbody>
<tr>
<td>Row 1</td>
</tr>
<tr>
<td>Row 2</td>
</tr>
<tr>
<td>Row 3</td>
</tr>
<tr>
<td>Row 4</td>
</tr>
</tbody>
</table>
<p>还可以使用特殊的标记来为超过两组元素添加风格。<a href="https://developer.mozilla.org/en/CSS/%3anth-child">文档中</a>对规则的描述不太准确，但是在例子中的“3”把元素分为三组，“+1”则是在组中的偏移量。在<a href="http://www.w3.org/TR/css3-selectors/#nth-child-pseudo">规范中</a>还有很多例子。</p>
<pre style="font-family: monospace;">tr<span style="color: #3333ff;">:nth-</span>child<span style="color: #00aa00;">(</span>3n<span style="color: #00aa00;">+</span>1<span style="color: #00aa00;">)</span> <span style="color: #00aa00;">{</span>  <span style="color: #000000; font-weight: bold;">background-color</span><span style="color: #00aa00;">:</span> <span style="color: #993333;">red</span><span style="color: #00aa00;">;</span> <span style="color: #00aa00;">}</span>
tr<span style="color: #3333ff;">:nth-</span>child<span style="color: #00aa00;">(</span>3n<span style="color: #00aa00;">+</span>2<span style="color: #00aa00;">)</span> <span style="color: #00aa00;">{</span>  <span style="color: #000000; font-weight: bold;">background-color</span><span style="color: #00aa00;">:</span> <span style="color: #993333;">green</span><span style="color: #00aa00;">;</span> <span style="color: #00aa00;">}</span>
tr<span style="color: #3333ff;">:nth-</span>child<span style="color: #00aa00;">(</span>3n<span style="color: #00aa00;">+</span>3<span style="color: #00aa00;">)</span> <span style="color: #00aa00;">{</span>  <span style="color: #000000; font-weight: bold;">background-color</span><span style="color: #00aa00;">:</span> <span style="color: #000000; font-weight: bold;">blue</span><span style="color: #00aa00;">;</span> <span style="color: #00aa00;">}</span></pre>
<p>实际的例子（需要Firefox 3.5）：</p>
<p><!-- #ex2 tr:nth-child(3n+1) {  background-color: red; } #ex2 tr:nth-child(3n+2) {  background-color: green; } #ex2 tr:nth-child(3n+3) {  background-color: blue; } --></p>
<table id="ex2" border="0">
<tbody>
<tr>
<td>Row 1</td>
</tr>
<tr>
<td>Row 2</td>
</tr>
<tr>
<td>Row 3</td>
</tr>
<tr>
<td>Row 4</td>
</tr>
<tr>
<td>Row 5</td>
</tr>
<tr>
<td>Row 6</td>
</tr>
</tbody>
</table>
<p><strong><a href="https://developer.mozilla.org/en/CSS/%3anth-last-child">:nth-last-child</a></strong></p>
<p><code>:nth-last-child</code>伪类同<code>:nth-child</code>的工作方式非常相似，不过他是从后向前数子节点：</p>
<pre style="font-family: monospace;">tr<span style="color: #3333ff;">:nth-last-</span>child<span style="color: #00aa00;">(</span>3n<span style="color: #00aa00;">+</span>3<span style="color: #00aa00;">)</span> <span style="color: #00aa00;">{</span>  <span style="color: #000000; font-weight: bold;">background-color</span><span style="color: #00aa00;">:</span> <span style="color: #993333;">red</span><span style="color: #00aa00;">;</span> <span style="color: #00aa00;">}</span>
tr<span style="color: #3333ff;">:nth-last-</span>child<span style="color: #00aa00;">(</span>3n<span style="color: #00aa00;">+</span>2<span style="color: #00aa00;">)</span> <span style="color: #00aa00;">{</span>  <span style="color: #000000; font-weight: bold;">background-color</span><span style="color: #00aa00;">:</span> <span style="color: #993333;">green</span><span style="color: #00aa00;">;</span> <span style="color: #00aa00;">}</span>
tr<span style="color: #3333ff;">:nth-last-</span>child<span style="color: #00aa00;">(</span>3n<span style="color: #00aa00;">+</span>1<span style="color: #00aa00;">)</span> <span style="color: #00aa00;">{</span>  <span style="color: #000000; font-weight: bold;">background-color</span><span style="color: #00aa00;">:</span> <span style="color: #000000; font-weight: bold;">blue</span><span style="color: #00aa00;">;</span> <span style="color: #00aa00;">}</span></pre>
<p>例子（需要Firefox 3.5）：</p>
<p><!-- #ex3 tr:nth-last-child(3n+3) {  background-color: red; } #ex3 tr:nth-last-child(3n+2) {  background-color: green; } #ex3 tr:nth-last-child(3n+1) {  background-color: blue; } --></p>
<table id="ex3" border="0">
<tbody>
<tr>
<td>Row 1</td>
</tr>
<tr>
<td>Row 2</td>
</tr>
<tr>
<td>Row 3</td>
</tr>
<tr>
<td>Row 4</td>
</tr>
<tr>
<td>Row 5</td>
</tr>
<tr>
<td>Row 6</td>
</tr>
</tbody>
</table>
<p><strong><a href="https://developer.mozilla.org/en/CSS/%3anth-of-type">:nth-of-type</a></strong></p>
<p><code>:nth-of-type</code>伪类使用跟其他伪类类似的语法，但是允许你根据元素类型进行选取。</p>
<pre style="font-family: monospace;">div<span style="color: #3333ff;">:nth-of-</span>type<span style="color: #00aa00;">(</span>odd<span style="color: #00aa00;">)</span> <span style="color: #00aa00;">{</span> <span style="color: #000000; font-weight: bold;">border-color</span><span style="color: #00aa00;">:</span> <span style="color: #993333;">red</span> <span style="color: #00aa00;">}</span>
div<span style="color: #3333ff;">:nth-of-</span>type<span style="color: #00aa00;">(</span>even<span style="color: #00aa00;">)</span> <span style="color: #00aa00;">{</span> <span style="color: #000000; font-weight: bold;">border-color</span><span style="color: #00aa00;">:</span> <span style="color: #000000; font-weight: bold;">blue</span> <span style="color: #00aa00;">}</span></pre>
<p>例子（需要Firefox 3.5）：</p>
<p><!-- #ex4 div { border-style: dotted; border-width: 3px; padding: 10px } #ex4 div:nth-of-type(odd) { border-color: red } #ex4 div:nth-of-type(even) { border-color: blue } --></p>
<div id="ex4">
<div>I should be red!</div>
<div>I should be blue!</div>
</div>
<p><strong><a href="https://developer.mozilla.org/en/CSS/%3anth-last-of-type">:nth-last-of-type</a></strong></p>
<p><code>:nth-last-of-type</code>同<code>:nth-of-type</code>功能类似，不过也是从后向前查子节点。</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.mozilla.com/chinacommunity/archives/776/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>颠覆网络35天 ─ 使用svg过滤器显示3D数据</title>
		<link>http://blog.mozilla.com/chinacommunity/archives/772</link>
		<comments>http://blog.mozilla.com/chinacommunity/archives/772#comments</comments>
		<pubDate>Tue, 11 Aug 2009 03:40:52 +0000</pubDate>
		<dc:creator>wzhao</dc:creator>
				<category><![CDATA[颠覆网络35天]]></category>

		<guid isPermaLink="false">http://blog.mozilla.com/chinacommunity/?p=772</guid>
		<description><![CDATA[原文地址：using svg filters to display 3D data 系列地址：颠覆网络35天 ==================================== 本演示作者为Hans Schmucker，他为Firefox 3.5制作了大量有趣的演示。明天我们还会介绍另外一个他制作的演示。 Hans使用CSS的filter属性和SVG过滤器实现了很多有趣的演示──使用Voxel数据渲染3D透视效果。Han在演示结尾的评论凸显Firefox 3.5的各项特性： 老实说，开始没有认为这个演示会成功，主要是因为这个过滤器非常非常的长。为了产生一帧的效果需要处理大概30个运算操作 （要为5个图层每个图层做4个操作+纹理处理5个操作+纹理变换的3个操作等），然后处理的一帧要覆盖768×512大小的表面。总而言之，需要大量的处 理工作，同时还要在速度上满足需要，但是这些工作在Firefox上都被完成的太出色了。 如果您对背景知识非常感兴趣，也请查看Hans的文章：使用6行SVG代码渲染透视纹理──文中他解释了如何使用过滤器来制作这些效果。我们来看看这个演示，非常的有趣。 在Firefox 3.5中查看演示]]></description>
			<content:encoded><![CDATA[<div>
<p>原文地址：<a href="http://hacks.mozilla.org/2009/06/svg-filter-3d-data/">using svg filters to display 3D data</a><br />
系列地址：<a href="http://www.mijia.org/blog/?cat=166">颠覆网络35天</a></p>
<p>====================================</p>
<p><em>本演示作者为<a href="http://www.tapper-ware.net/">Hans Schmucker</a>，他为Firefox 3.5制作了大量有趣的演示。明天我们还会介绍另外一个他制作的演示。</em></p>
<p>Hans使用<a href="https://developer.mozilla.org/web-tech/2008/09/15/svg-effects-for-html-content/">CSS的<code>filter</code>属性</a>和<a href="https://developer.mozilla.org/En/SVG_in_Firefox">SVG过滤器</a>实现了很多有趣的演示──使用<a href="http://en.wikipedia.org/wiki/Voxel">Voxel</a>数据渲染3D透视效果。Han在演示结尾的评论凸显Firefox 3.5的各项特性：</p>
<blockquote><p>老实说，开始没有认为这个演示会成功，主要是因为这个过滤器非常非常的长。为了产生一帧的效果需要处理大概30个运算操作 （要为5个图层每个图层做4个操作+纹理处理5个操作+纹理变换的3个操作等），然后处理的一帧要覆盖768×512大小的表面。总而言之，需要大量的处 理工作，同时还要在速度上满足需要，但是这些工作在Firefox上都被完成的太出色了。</p></blockquote>
<p>如果您对背景知识非常感兴趣，也请查看Hans的文章：<a href="http://www.tapper-ware.net/2009/05/perspective-texture-with-6-lines-of-svg.html"><em>使用6行SVG代码渲染透视纹理</em></a>──文中他解释了如何使用过滤器来制作这些效果。我们来看看这个演示，非常的有趣。</p>
<div style="font-size: 120%;"><a href="http://www.tapper-ware.net/stable/web.filter.voxels/index.xhtml" target="_blank">在Firefox 3.5中查看演示<br />
<img src="http://www.tapper-ware.net/stable/web.filter.voxels/screen.png" alt="" /></a></div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.mozilla.com/chinacommunity/archives/772/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>颠覆网络35天 ─ Firefox 3.5中的透明度</title>
		<link>http://blog.mozilla.com/chinacommunity/archives/769</link>
		<comments>http://blog.mozilla.com/chinacommunity/archives/769#comments</comments>
		<pubDate>Mon, 10 Aug 2009 03:55:49 +0000</pubDate>
		<dc:creator>wzhao</dc:creator>
				<category><![CDATA[颠覆网络35天]]></category>

		<guid isPermaLink="false">http://blog.mozilla.com/chinacommunity/?p=769</guid>
		<description><![CDATA[原文地址：opacity in Firefox 3.5 系列地址：颠覆网络35天 ==================================== 这篇博客非常的短，不过我觉得非常有必要在这里写一下，因为大家通过这个可以了解到浏览器的特性是如何从某个制作者实现发展成全面支持的标准的。 在Firefox 3.5中，我们不会再支持Mozilla特化的一条CSS属性-moz-opacity。开发人员可以使用标准化的opacity属性来为元素设定透明度。 我们从Firefox 0.9开始引入属性opacity并且把-moz-opacity设定为deprecated属性。现在在Firefox 3.5中，我们正式的删除了-moz-opacity。 对于一个简单的属性来说，这个标准化的道路算是漫长了，不过非常值得一提，因为他能够让人们了解在所有这些标准化过程中，时间和进程可能是多么的漫长，:)]]></description>
			<content:encoded><![CDATA[<div>
<p>原文地址：<a href="http://hacks.mozilla.org/2009/06/opacity/">opacity in Firefox 3.5</a><br />
系列地址：<a href="http://www.mijia.org/blog/?cat=166">颠覆网络35天</a></p>
<p>====================================</p>
<p>这篇博客非常的短，不过我觉得非常有必要在这里写一下，因为大家通过这个可以了解到浏览器的特性是如何从某个制作者实现发展成全面支持的标准的。</p>
<p>在Firefox 3.5中，我们不会再支持Mozilla特化的一条CSS属性<code>-moz-opacity</code>。开发人员可以使用标准化的<code><a href="https://developer.mozilla.org/en/CSS/opacity">opacity</a></code>属性来为元素设定透明度。</p>
<p>我们从Firefox 0.9开始引入属性<code>opacity</code>并且把<code>-moz-opacity</code>设定为deprecated属性。现在在Firefox 3.5中，我们正式的删除了<code>-moz-opacity</code>。</p>
<p>对于一个简单的属性来说，这个标准化的道路算是漫长了，不过非常值得一提，因为他能够让人们了解在所有这些标准化过程中，时间和进程可能是多么的漫长，:)</p></div>
]]></content:encoded>
			<wfw:commentRss>http://blog.mozilla.com/chinacommunity/archives/769/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>颠覆网络35天 ─ 使用MozAfterPaint调试绘图</title>
		<link>http://blog.mozilla.com/chinacommunity/archives/765</link>
		<comments>http://blog.mozilla.com/chinacommunity/archives/765#comments</comments>
		<pubDate>Fri, 07 Aug 2009 07:42:35 +0000</pubDate>
		<dc:creator>wzhao</dc:creator>
				<category><![CDATA[颠覆网络35天]]></category>

		<guid isPermaLink="false">http://blog.mozilla.com/chinacommunity/?p=765</guid>
		<description><![CDATA[原文地址：debugging painting with MozAfterPaint 系列地址：颠覆网络35天 ==================================== 本文作者为Robert O’Callahan，本来发布在Mozilla的互联网技术博客上。其中描述的特性是Firefox 3.5中非常有趣的特性，非常值得我们在35天计划中重新发布一次。 另外，Thomas Robinson为此作了一个非常方便的bookmarklet，方便在浏览器中调试页面绘图。 为了满足很多开发者的需求，我们在Firefox 3.5中提供了一个非常实验性质的API──在页面内容每次被绘画时激发相应事件。这个事件叫做MozAfterPaint，由文档对象激发，一直冒泡到window对象。事件提供两个属性：clientRects 和 boundingClientRect──用来表明什么被重画，同getClientRects 和 getBoundingClientRect方法使用相同的对象和坐标系统。 这对Firefox的扩展是非常有用的特性，或者是其他的“chrome”的代码例如使用canvas.drawWindow方法来截取窗体内容等。可能对类似Firebug之类的工具也会有用。同样，假如你希望向页面添加一些JavaScript代码来测量Firefox重画的区域、对象等等情况也会非常有用。 注意： 这个事件仅在Gecko引擎上提供。不要在公开的网页上使用这些功能──现在也没有看到有任何人会在公共网页上使用，因此也不知道这个事件会不会得到标准化的支持。 由于安全原因，普通网页内容仅仅会接收他自己文档中激发的重画事件──IFRAME内激发的重画不会报告给该IFRAME父辈对象上挂接的非安全监听器。 目前，该事件可能会在实际重画发生前被激发出。不过这应该不会有什么影响，我们将来也会解决这个问题。 如果你的事件处理程序做了某些再次激发重画的事情，例如改变元素的风格，你可能激发了一个死循环。你的浏览器可能还有反应，不过你的机器会着实为世界变暖贡献很多 ：） 在可视范围外滚动区域的重画也会被激发，但是如果该区域元素具有overflow:auto属性的话就不会被激发。 在窗口内插件（plugins，大部分在Windows和GTK上的plugins）的重画事件不会被激发。]]></description>
			<content:encoded><![CDATA[<div>
<p>原文地址：<a href="http://hacks.mozilla.org/2009/06/mozafterpaint/">debugging painting with MozAfterPaint</a><br />
系列地址：<a href="http://www.mijia.org/blog/?cat=166">颠覆网络35天</a></p>
<p>====================================</p>
<p><em>本文作者为Robert O’Callahan，本来<a href="https://developer.mozilla.org/web-tech/2008/10/13/mozafterpaint/">发布在</a>Mozilla的<a href="https://developer.mozilla.org/web-tech/">互联网技术博客上</a>。其中描述的特性是Firefox 3.5中非常有趣的特性，非常值得我们在35天计划中重新发布一次。</em></p>
<p><em>另外，Thomas Robinson为此作了一个非常方便的<a href="http://tlrobinson.net/blog/2008/10/14/improved-browser-paint-events-bookmarklet/">bookmarklet</a>，方便在浏览器中调试页面绘图。</em></p>
<p>为了满足很多开发者的需求，我们在Firefox 3.5中提供了一个<em>非常</em>实验性质的API──在页面内容每次被绘画时激发相应事件。这个事件叫做<code>MozAfterPaint</code>，由文档对象激发，一直冒泡到window对象。事件提供<a href="http://mxr.mozilla.org/mozilla-central/source/dom/public/idl/events/nsIDOMNotifyPaintEvent.idl">两个属性</a>：<code>clientRects</code> 和 <code>boundingClientRect</code>──用来表明什么被重画，同<a href="http://developer.mozilla.org/en/DOM/element.getClientRects">getClientRects</a> 和 <a href="http://developer.mozilla.org/En/DOM:element.getBoundingClientRect">getBoundingClientRect</a>方法使用相同的对象和坐标系统。</p>
<p>这对Firefox的扩展是<a href="http://www.oxymoronical.com/blog/2008/10/How-extensions-can-slow-down-Firefox-my-dirty-little-secret">非常有用的特性</a>，或者是其他的“chrome”的代码例如使用canvas.drawWindow方法来截取窗体内容等。可能对类似Firebug之类的工具也会有用。同样，假如你希望向页面添加一些JavaScript代码来测量Firefox重画的区域、对象等等情况也会非常有用。</p>
<p><strong>注意</strong>：</p>
<ul>
<li>这个事件仅在Gecko引擎上提供。不要在公开的网页上使用这些功能──现在也没有看到有任何人会在公共网页上使用，因此也不知道这个事件会不会得到标准化的支持。</li>
<li>由于安全原因，普通网页内容仅仅会接收他自己文档中激发的重画事件──IFRAME内激发的重画不会报告给该IFRAME父辈对象上挂接的非安全监听器。</li>
<li>目前，该事件可能会在实际重画发生前被激发出。不过这应该不会有什么影响，我们将来也会解决这个问题。</li>
<li>如果你的事件处理程序做了某些再次激发重画的事情，例如改变元素的风格，你可能激发了一个死循环。你的浏览器可能还有反应，不过你的机器会着实为世界变暖贡献很多 ：）</li>
<li>在可视范围外滚动区域的重画也会被激发，但是如果该区域元素具有overflow:auto属性的话就不会被激发。</li>
<li>在窗口内插件（plugins，大部分在Windows和GTK上的plugins）的重画事件不会被激发。</li>
</ul>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.mozilla.com/chinacommunity/archives/765/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>颠覆网络35天 ─ 连接互联网和HTML5 video</title>
		<link>http://blog.mozilla.com/chinacommunity/archives/754</link>
		<comments>http://blog.mozilla.com/chinacommunity/archives/754#comments</comments>
		<pubDate>Thu, 06 Aug 2009 05:36:06 +0000</pubDate>
		<dc:creator>wzhao</dc:creator>
				<category><![CDATA[颠覆网络35天]]></category>

		<guid isPermaLink="false">http://blog.mozilla.com/chinacommunity/?p=754</guid>
		<description><![CDATA[原文地址：connecting html5 video to the web 系列地址：颠覆网络35天 ==================================== 这是Christopher Blizzard在2009年6月19日在开放视频大会上做得一次演示。演示本身是由一直超牛的Paul Rouget制作的。 观看video 下载.ogv格式 或者 .mp4格式。在blip.tv可以在线观看。 [译注] HTML 5的video标签不仅仅是允许直接在浏览器中播放一定格式的视频，也不是说如何制作超炫的播放器。HTML5 video允许HTML的任何其他元素同video进行交互，这也是该演示希望展示出的特性。所以文章标题叫做如何连接互联网和HTML5 video。在视频中可以看到如何在视频中加入twitter最新状态的更新、如何进行人脸识别等等，这些是比传统视频更加炫的特性。]]></description>
			<content:encoded><![CDATA[<div>
<p>原文地址：<a href="http://hacks.mozilla.org/2009/06/connecting-html5-video/">connecting html5 video to the web</a><br />
系列地址：<a href="http://www.mijia.org/blog/?cat=166">颠覆网络35天</a></p>
<p>====================================</p>
<p><em>这是Christopher Blizzard在2009年6月19日在<a href="http://openvideoconference.org/">开放视频大会</a>上做得一次演示。演示本身是由一直超牛的<a href="http://blog.mozbox.org/">Paul Rouget</a>制作的。</em></p>
<p><em></em>观看<a href="http://videos.mozilla.org/serv/blizzard/35days/face-detection/face-off-480.ogv">video</a></p>
<p>下载<a href="http://videos.mozilla.org/serv/blizzard/35days/face-detection/face-off-480.ogv">.ogv格式</a> 或者 <a href="http://videos.mozilla.org/serv/blizzard/35days/face-detection/face-off-480.mp4">.mp4格式</a>。在<a href="http://blip.tv/file/2265515">blip.tv</a>可以在线观看。</p>
<p>[译注] HTML 5的video标签不仅仅是允许直接在浏览器中播放一定格式的视频，也不是说如何制作超炫的播放器。HTML5 video允许HTML的任何其他元素同video进行交互，这也是该演示希望展示出的特性。所以文章标题叫做如何连接互联网和HTML5 video。在视频中可以看到如何在视频中加入twitter最新状态的更新、如何进行人脸识别等等，这些是比传统视频更加炫的特性。</p></div>
]]></content:encoded>
			<wfw:commentRss>http://blog.mozilla.com/chinacommunity/archives/754/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
<enclosure url="http://videos.mozilla.org/serv/blizzard/35days/face-detection/face-off-480.ogv" length="7893997" type="video/ogg" />
		</item>
		<item>
		<title>颠覆网络35天 ─ Firefox 3.5中的DOM遍历</title>
		<link>http://blog.mozilla.com/chinacommunity/archives/745</link>
		<comments>http://blog.mozilla.com/chinacommunity/archives/745#comments</comments>
		<pubDate>Wed, 05 Aug 2009 08:34:40 +0000</pubDate>
		<dc:creator>wzhao</dc:creator>
				<category><![CDATA[颠覆网络35天]]></category>

		<guid isPermaLink="false">http://blog.mozilla.com/chinacommunity/?p=745</guid>
		<description><![CDATA[原文地址：DOM Traversal in Firefox 3.5 系列地址：颠覆网络35天 ==================================== Firefox 3.5中包含了两个全新的W3C DOM遍历规范实现。第一个，元素遍历API，主要针对逐个元素的遍历更简便；第二个，NodeIterator接口，允许更加容易的找到任何节点。 元素遍历API 元素遍历API的目的是为开发人员提供更加简单的方法来遍历DOM元素，不用在担心文本节点、注释节点等等。这曾经是开发人员的一剂毒药，例如使用document.documentElement.firstChild经常会产生不同的结果，可能仅仅是因为文档结构中多个空格，造成多个文本节点之类的。 元素遍历API提供一系列新的DOM节点属性。 这里是一份完整的现存DOM节点属性和全新副本的细分列表： 目的 所有DOM节点 仅DOM元素 第一个 .firstChild .firstElementChild 最后一个 .lastChild .lastElementChild 前一个 .previousSibling .previousElementSibling 下一个 .nextSibling .nextElementSibling 长度 .childNodes.length .childElementCount 这些属性为DOM规范作了有效补充（老实说，真应该从开始就有这些属性）。 不过还是有一个属性一如既往的缺失：.childElements（对应于.childNodes）。这个属性（包含DOM元素的所有子元素的NodeSet）在规范的前个版本中提出过，不过在最后貌似没有通过。 不过也差不多了，现在IE、Opera和Safari都支持.children属性可以提供类似于.childElements的功能集合。元素遍历API在Firefox 3.5的实现中也包括了.children。这就意味着在所有主流浏览器中都支持这一属性。（不过离所有浏览器支持其他真正的元素遍历规范还比较远。） 一些使用元素遍历API（以及.children）的代码示例： 点击发生时显示下个元素： someElement.addEventListener(“click”, function(){ this.nextElementSibling.style.display = “block”; }, false); 为所有子元素添加class： for ( var i = 0; i &#60; someElement.children.length; [...]]]></description>
			<content:encoded><![CDATA[<div>
<p>原文地址：<a href="http://hacks.mozilla.org/2009/06/dom-traversal/">DOM Traversal in Firefox 3.5</a><br />
系列地址：<a href="http://www.mijia.org/blog/?cat=166">颠覆网络35天</a></p>
<p>====================================</p>
<p>Firefox 3.5中包含了两个全新的W3C DOM遍历规范实现。第一个，<a href="http://www.w3.org/TR/ElementTraversal/">元素遍历API</a>，主要针对逐个元素的遍历更简便；第二个，<a href="http://www.w3.org/TR/DOM-Level-2-Traversal-Range/traversal">NodeIterator</a>接口，允许更加容易的找到任何节点。</p>
<p><strong>元素遍历API</strong></p>
<p><a href="http://www.w3.org/TR/ElementTraversal/">元素遍历API</a>的目的是为开发人员提供更加简单的方法来遍历DOM元素，不用在担心文本节点、注释节点等等。这曾经是开发人员的一剂毒药，例如使用<code>document.documentElement.firstChild</code>经常会产生不同的结果，可能仅仅是因为文档结构中多个空格，造成多个文本节点之类的。</p>
<p>元素遍历API提供一系列<a href="http://dev.w3.org/2006/webapi/ElementTraversal/publish/ElementTraversal.html#ecmascript-bindings">新的DOM节点属性</a>。</p>
<p>这里是一份完整的现存DOM节点属性和全新副本的细分列表：</p>
<table border="0">
<tbody>
<tr>
<th>目的</th>
<th>所有DOM节点</th>
<th>仅DOM元素</th>
</tr>
<tr>
<td>第一个</td>
<td>.firstChild</td>
<td>.firstElementChild</td>
</tr>
<tr>
<td>最后一个</td>
<td>.lastChild</td>
<td>.lastElementChild</td>
</tr>
<tr>
<td>前一个</td>
<td>.previousSibling</td>
<td>.previousElementSibling</td>
</tr>
<tr>
<td>下一个</td>
<td>.nextSibling</td>
<td>.nextElementSibling</td>
</tr>
<tr>
<td>长度</td>
<td>.childNodes.length</td>
<td>.childElementCount</td>
</tr>
</tbody>
</table>
<p>这些属性为DOM规范作了有效补充（老实说，真应该从开始就有这些属性）。</p>
<p>不过还是有一个属性一如既往的缺失：<code>.childElements</code>（对应于<code>.childNodes</code>）。这个属性（包含DOM元素的所有子元素的NodeSet）在规范的前个版本中提出过，不过在最后貌似没有通过。</p>
<p>不过也差不多了，现在IE、Opera和Safari都支持<code>.children</code>属性可以提供类似于<code>.childElements</code>的功能集合。元素遍历API在Firefox 3.5的实现中也包括了<code>.children</code>。这就意味着在所有主流浏览器中都支持这一属性。（不过离所有浏览器支持其他真正的元素遍历规范还比较远。）</p>
<p>一些使用元素遍历API（以及<code>.children</code>）的代码示例：</p>
<p>点击发生时显示下个元素：</p>
<pre style="font-family: monospace;">someElement.<span style="color: #660066;">addEventListener</span><span style="color: #009900;">(</span><span style="color: #3366cc;">“click”</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #009900;">{</span>
    <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">nextElementSibling</span>.<span style="color: #660066;">style</span>.<span style="color: #660066;">display</span> <span style="color: #339933;">=</span> <span style="color: #3366cc;">“block”</span><span style="color: #339933;">;</span>
<span style="color: #009900;">}</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span></pre>
<p>为所有子元素添加class：</p>
<pre style="font-family: monospace;"><span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">(</span> <span style="color: #003366; font-weight: bold;">var</span> i <span style="color: #339933;">=</span> <span style="color: #cc0000;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> someElement.<span style="color: #660066;">children</span>.<span style="color: #660066;">length</span><span style="color: #339933;">;</span> i<span style="color: #339933;">++</span> <span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
    someElement.<span style="color: #660066;">children</span><span style="color: #009900;">[</span> i <span style="color: #009900;">]</span>.<span style="color: #660066;">className</span> <span style="color: #339933;">=</span> <span style="color: #3366cc;">“active”</span><span style="color: #339933;">;</span>
<span style="color: #009900;">}</span></pre>
<p><strong>NodeIterator API</strong></p>
<p>NodeIterator是一个比较旧的API，不过一直没有被广泛支持，现在在Firefox 3.5中开始支持。<a href="https://developer.mozilla.org/En/DOM/NodeIterator">NodeIterator API</a>被设计为简便快捷的在DOM文档中遍历所有节点（包括文本节点、注释节点等）。</p>
<p>API本身有点让人费解（包含一些开发人员根本不在意的特性），但是如果你希望使用他，还是非常简便的。</p>
<p>API通过生成一个NodeIterator（使用<code>document.createNodeIterator</code>）并传入一系列过滤器来遍历节点。NodeIterator可以返回文档中所有节点（或者在某个给点节点下所有节点），然后你会希望对他进行过滤仅仅给出你需要的。可以看看下面的例子。</p>
<p>生成NodeIterator遍历文档中所有的注释节点：</p>
<pre style="font-family: monospace;"><span style="color: #003366; font-weight: bold;">var</span> nodeIterator <span style="color: #339933;">=</span> document.<span style="color: #660066;">createNodeIterator</span><span style="color: #009900;">(</span>
    document<span style="color: #339933;">,</span>
    NodeFilter.<span style="color: #660066;">SHOW_COMMENT</span><span style="color: #339933;">,</span>
    <span style="color: #003366; font-weight: bold;">null</span><span style="color: #339933;">,</span>
    <span style="color: #003366; font-weight: bold;">false</span>
<span style="color: #009900;">)</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">var</span> node<span style="color: #339933;">;</span>
<span style="color: #000066; font-weight: bold;">while</span> <span style="color: #009900;">(</span> <span style="color: #009900;">(</span>node <span style="color: #339933;">=</span> nodeIterator.<span style="color: #660066;">nextNode</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #009900;">)</span> <span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
    node.<span style="color: #660066;">parentNode</span>.<span style="color: #660066;">removeChild</span><span style="color: #009900;">(</span> node <span style="color: #009900;">)</span><span style="color: #339933;">;</span>
<span style="color: #009900;">}</span></pre>
<p>NodeIterator是双向链表似的结构（可以在任何方向上移动，使用<a href="https://developer.mozilla.org/En/DOM/NodeIterator.previousNode">previousNode</a> 或者 <a href="https://developer.mozilla.org/En/DOM/NodeIterator.nextNode">nextNode</a>）。</p>
<p>也许使用这个API最合适的地方是用来遍历最常用的（但是最难遍历的）节点，例如注释和文本节点～～</p></div>
]]></content:encoded>
			<wfw:commentRss>http://blog.mozilla.com/chinacommunity/archives/745/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

