﻿<?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; 网站前端</title>
	<atom:link href="http://www.icyfire.me/category/programmer/web/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.icyfire.me</link>
	<description>太阳底下没有新鲜事。</description>
	<lastBuildDate>Tue, 31 Jan 2012 02:50:19 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>[翻译]看图学Javascript Part II</title>
		<link>http://www.icyfire.me/2011/10/object-graphs-2/</link>
		<comments>http://www.icyfire.me/2011/10/object-graphs-2/#comments</comments>
		<pubDate>Mon, 31 Oct 2011 09:42:58 +0000</pubDate>
		<dc:creator>icyfire</dc:creator>
				<category><![CDATA[网站前端]]></category>
		<category><![CDATA[Javascript]]></category>

		<guid isPermaLink="false">http://www.icyfire.me/?p=1222</guid>
		<description><![CDATA[<img src="http://www.icyfire.me/wp-content/uploads/2011/10/classical.png" alt="" title="classical" width="640" height="292" class="alignnone size-full wp-image-1227" />

第一篇使用图像描述Javascript语法的文章很受欢迎，所以我决定使用这个方法进行一些更加高级的想法。在这片文章里，我将会解释创建对象的三个常用技术。它们是使用原型的构造函数，纯原型以及对象工厂。

我的目标是想帮助大家明白每种技术的优点和弱点，并且明白它们具体是怎样运作的。 <a href="http://www.icyfire.me/2011/10/object-graphs-2/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<style>
#content .snippet dl:last-child {border-bottom-left-radius: 10px;border-bottom-right-radius: 10px;font-family: monaco,consolas,monospace;}
#content .snippet .output {background-color: #F0FFF0;}
#content .snippet dl {background-color: #F6F5F4;border: 1px solid #AAAAAA;font-size: 90%;margin: 0 0 12px 0;padding: 10px;}
#content .snippet dt {float: right;font-family: sans-serif;font-weight: bold; color: #779977;}
#content .snippet dd {margin-bottom:0;padding: 0;}
</style>
<p>第一篇使用图像描述Javascript语法的文章很受欢迎，所以我决定使用这个方法进行一些更加高级的想法。在这片文章里，我将会解释创建对象的三个常用技术。它们是使用原型的构造函数，纯原型以及对象工厂。</p>
<p>我的目标是想帮助大家明白每种技术的优点和弱点，并且明白它们具体是怎样运作的。</p>
<h2 style="font-weight:bold;color:#570E00;">经典的Javascript构造函数（Classical JavaScript Constructors）</h2>
<p>首先，我们用原型创建一个简单的构造函数。这是在原生的Javascript里你能找到的最接近类的东西。它很强大和高效，但是跟你所期待的其他语言的类比起来并不太一样。</p>
<pre class="brush: javascript; gutter: true">function Rectangle(width, height) {
  this.width = width;
  this.height = height;
}
Rectangle.prototype.getArea = function getArea() {
  return this.width * this.height;
};
Rectangle.prototype.getPerimeter = function getPerimeter() {
  return 2 * (this.width + this.height);
};
Rectangle.prototype.toString = function toString() {
  return this.constructor.name + " a=" + this.getArea() + " p=" + this.getPerimeter();
};</pre>
<p>现在我们定义一个继承自Rectangle叫Square的类。要进行继承，构造函数的原型必须继承自父构造函数的原型。这里我们重写getPerimeter让它稍微高效点，同时也看看怎样重写一个函数。</p>
<pre class="brush: javascript; gutter: true">function Square(side) {
  this.width = side;
  this.height = side;
}
Square.prototype.__proto__ = Rectangle.prototype;
Square.prototype.getPerimeter = function getPerimeter() {
  return this.width * 4;
};</pre>
<p>用法很直接，分别创建一个实例并调用它们的函数。</p>
<pre class="brush: javascript; gutter: true">var rect = new Rectangle(6, 4);
var sqr = new Square(5);
console.log(rect.toString())
console.log(sqr.toString())</pre>
<div class="snippet">
<dl class="output">
<dt>输出</dt>
<dd>
<div class="last-expression">Rectangle a=24 p=20<br />Square a=25 p=20</div>
</dd>
</dl>
</div>
<p>下面是结果的数据结构，虚线表示对象的继承。</p>
<p><img src="http://www.icyfire.me/wp-content/uploads/2011/10/classical.png" alt="" title="classical" width="640" height="292" class="alignnone size-full wp-image-1227" /></p>
<p>注意到rect实例跟Square.prototype没啥不同。它们都是从Rectangle.prototype继承而来的简单对象。当你深入了解Javascript你会发现它只是一系列对象的连接。唯一比较特别的对象就是函数，它们可以接受参数和含有可执行的代码，并把它指向作用域。</p>
<h2 style="font-weight:bold;color:#570E00;">纯原型对象（Pure Prototypal Objects）</h2>
<p>让我们举些不使用构造函数的例子。这次我们只使用纯原型实现。</p>
<p>我们定义一个Rectangle原型，作为我们所有对象的一个模型。</p>
<pre class="brush: javascript; gutter: true">var Rectangle = {
  name: "Rectangle",
  getArea: function getArea() {
    return this.width * this.height;
  },
  getPerimeter: function getPerimeter() {
    return 2 * (this.width + this.height);
  },
  toString: function toString() {
    return this.name + " a=" + this.getArea() + " p=" + this.getPerimeter();
  }
};</pre>
<p>现在我们定义一个子对象Square并重写一些属性以改变一些特性。</p>
<pre class="brush: javascript; gutter: true">var Square = {
  name: "Square",
  getArea: function getArea() {
    return this.width * this.width;
  },
  getPerimeter: function getPerimeter() {
    return this.width * 4;
  },
};
Square.__proto__ = Rectangle;</pre>
<p>要创建这些原型的实例，我们只需要简单的创建继承自这些原型对象的新对象，然后设置它们的自己的属性。</p>
<pre class="brush: javascript; gutter: true">var rect = Object.create(Rectangle);
rect.width = 6;
rect.height = 4;
var square = Object.create(Square);
square.width = 5;
console.log(rect.toString());
console.log(square.toString());</pre>
<div class="snippet">
<dl class="output">
<dt>输出</dt>
<dd>
<div class="last-expression">Rectangle a=24 p=20<br />Square a=25 p=20</div>
</dd>
</dl>
</div>
<p>下面是结果的对象图。</p>
<p><img src="http://www.icyfire.me/wp-content/uploads/2011/10/prototypal.png" alt="" title="prototypal" width="640" height="243" class="alignnone size-full wp-image-1229" /></p>
<p>这个方法没有构造函数+原型的方法强大，但是它比较容易理解，因为它使用的继承比较少。而且如果你之前的语言也是使用这种纯原型的方式实现的话，那么你应该会觉得高兴Javascript也能这么干。</p>
<h2 style="font-weight:bold;color:#570E00;">对象工厂（Object Factories）</h2>
<p>我最喜欢的其中一个创建对象的方法就是使用工厂方法。它的不同之处在于它不用创建一个包含共享函数的原型对象然后创建实例，我只需要每次简单的调用一个函数然后返回一个新对象就行了。</p>
<p>这个例子是一个超级简单的MVC架构。Controller函数把Model跟View作为参数传入然后输出一个新的Controller对象。所有的状态都通过作用域保存在一个闭包里。</p>
<pre class="brush: javascript; gutter: true">function Controller(model, view) {
  view.update(model.value);
  return {
    up: function onUp(evt) {
      model.value++;
      view.update(model.value);
    },
    down: function onDown(evt) {
      model.value--;
      view.update(model.value);
    },
    save: function onSave(evt) {
      model.save();
      view.close();
    }
  };
}</pre>
<p>要使用它，只需要简单调用这个函数并传入你想传入的参数。看下我们是怎样直接把它们用作事件句柄（setTimeout）而不必先把函数绑定到对象上。而且它（函数）并没有在内部使用this，所以没有必要烦恼this的值这个问题了。</p>
<pre class="brush: javascript; gutter: true">var on = Controller(
  // Inline a mock model
  {
    value: 5,
    save: function save() {
      console.log("Saving value " + this.value + " somewhere");
    }
  },
  // Inline a mock view
  {
    update: function update(newValue) {
      console.log("View now has " + newValue);
    },
    close: function close() {
      console.log("Now hiding view");
    }
  }
);
setTimeout(on.up, 100);
setTimeout(on.down, 200);
setTimeout(on.save, 300);</pre>
<div class="snippet">
<dl class="output">
<dt>输出</dt>
<dd>
<div class="last-expression">View now has 5<br />View now has 6<br />View now has 5<br />Saving value 5 somewhere<br />Now hiding view</div>
</dd>
</dl>
</div>
<p>下面是这段代码的结果的对象图。注意到我们通过函数的隐藏[scope]属性访问了两个传入的匿名对象，换句话说，我们访问了用工厂方法创建的闭包里的Model和View。</p>
<p><img src="http://www.icyfire.me/wp-content/uploads/2011/10/factory.png" alt="" title="factory" width="640" height="244" class="alignnone size-full wp-image-1228" /></p>
<h2 style="font-weight:bold;color:#570E00;">总结</h2>
<p>我没有更多想要说的了，但是我想保持这篇文章短小精悍。如果有需要的话，我会写第三篇讲解如何写ruby式的Mixin以及其他进阶的话题。</p>
<p>原文：<a href="http://howtonode.org/object-graphs-2" target="_blank">http://howtonode.org/object-graphs-2</a></p>
<p>Translated by icyfire @ 2011-10-31</p>
]]></content:encoded>
			<wfw:commentRss>http://www.icyfire.me/2011/10/object-graphs-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[翻译]看图学Javascript Part I</title>
		<link>http://www.icyfire.me/2011/10/object-graphs-1/</link>
		<comments>http://www.icyfire.me/2011/10/object-graphs-1/#comments</comments>
		<pubDate>Fri, 28 Oct 2011 11:01:42 +0000</pubDate>
		<dc:creator>icyfire</dc:creator>
				<category><![CDATA[网站前端]]></category>
		<category><![CDATA[Javascript]]></category>

		<guid isPermaLink="false">http://www.icyfire.me/?p=1160</guid>
		<description><![CDATA[<img src="http://www.icyfire.me/wp-content/uploads/2011/09/aa776_functions.png" alt="" title="函数" width="544" height="393" class="alignnone size-full wp-image-1174" />

要想成为一个出色的Javascript开发者，其中一个秘密就是真正的去理解这门语言。这篇文章将会用一些简单易懂的图表来解释Javasript的一些基本要素。 <a href="http://www.icyfire.me/2011/10/object-graphs-1/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<style>
#content .snippet dl:last-child {border-bottom-left-radius: 10px;border-bottom-right-radius: 10px;font-family: monaco,consolas,monospace;}
#content .snippet .output {background-color: #F0FFF0;}
#content .snippet dl {background-color: #F6F5F4;border: 1px solid #AAAAAA;font-size: 90%;margin: 0 0 12px 0;padding: 10px;}
#content .snippet dt {float: right;font-family: sans-serif;font-weight: bold; color: #779977;}
#content .snippet dd {margin-bottom:0;padding: 0;}
</style>
<p>要想成为一个出色的Javascript开发者，其中一个秘密就是真正的去理解这门语言。这篇文章将会用一些简单易懂的图表来解释Javasript的一些基本要素。</p>
<h2 style="font-weight:bold;color:#570E00;">无处不在的引用（References Everywhere）</h2>
<p>Javascript里的变量简单来说就是一个引用了内存里某个值的标签。这个值可以是字符串，数字或者布尔值这些基本元素，也可以是对象或者函数。</p>
<h3 style="font-weight:bold;color:#570E00;">局部变量（Local Variables）</h3>
<p>在下面的例子里，我们会在顶级作用域里创建四个局部变量然后把它们指向一些基本类型的值：</p>
<pre class="brush: javascript; gutter: true">
// Let's create some local variables in the top scope
var name = "Tim Caswell";
var age = 28;
var isProgrammer = true;
var likesJavaScript = true;
// Test to see if the two variables reference the same value
isProgrammer === likesJavaScript;
</pre>
<div class="snippet">
<dl class="output">
<dt>输出</dt>
<dd>
<div class="last-expression">=&gt; true</div>
</dd>
</dl>
</div>
<p><img src="http://www.icyfire.me/wp-content/uploads/2011/09/2d2c2_variables.png" alt="" title="局部变量" width="323" height="203" class="alignnone size-full wp-image-1170" /></p>
<p>注意到两个布尔型变量指向了内存里的同一个值。这是因为基本元素是不可变的（immutable），解析器可以进行优化，对这些值的引用分享同一个实例。<br />
在这段代码中，我们用 === 来检验两个引用是不是指向同一个值，结果返回是true。<br />
在外层的代码处于最外层的闭包作用域（The outer box represents the outermost closure scope.），这些变量是顶级的局部变量，不要跟global/window对象的属性相混淆。</p>
<h3 style="font-weight:bold;color:#570E00;">对象与原型链（Objects and Prototype Chains）</h3>
<p>对象就是一个集合，包含了更多的对新对象与原型的引用。唯一特别的地方是当你试图访问一个在父对象里而不在局部对象里的属性时所用到的原型链。</p>
<pre class="brush: javascript; gutter: true">
// Create a parent object
var tim = {
  name: "Tim Caswell",
  age: 28,
  isProgrammer: true,
  likesJavaScript: true
}
// Create a child object
var jack = Object.create(tim);
// Override some properties locally
jack.name = "Jack Caswell";
jack.age = 4;
// Look up stuff through the prototype chain
jack.likesJavaScript;
</pre>
<div class="snippet">
<dl class="output">
<dt>输出</dt>
<dd>
<div class="last-expression">=&gt; true</div>
</dd>
</dl>
</div>
<p><img src="http://www.icyfire.me/wp-content/uploads/2011/09/91909_objects.png" alt="对象" title="对象" width="611" height="337" class="alignnone size-full wp-image-1173" /></p>
<p>这里我们有一个具有四个属性的对象，被变量tim所引用。同时我们创建了一个由第一个对象继承而来的新对象，被变量jack所引用。然后我们重写这个局部对象中的两个属性。<br />
当我们要访问jack.likesJavaScript的时候，我们先会查找jack所引用的对象，然后在其中查找likesJavaScript这个属性。对象里没有这个属性，于是我们在父对象里进行查找并找到了它，并知道它引用了值true。</p>
<h3 style="font-weight:bold;color:#570E00;">全局对象（The Global Object）</h3>
<p>曾经有疑问为什么像jslint这些工具老是告诉你不要忘记用var定义变量，好吧，让我告诉你如果你忘记了的话。</p>
<pre class="brush: javascript; gutter: true">
var name = "Tim Caswell";
var age = 28;
var isProgrammer = true;
// Oops we forgot a var
likesJavaScript = true;
</pre>
<p><img src="http://www.icyfire.me/wp-content/uploads/2011/09/7857c_globals.png" alt="" title="全局对象" width="440" height="246" class="alignnone size-full wp-image-1172" /></p>
<p>注意到likesJavaScript现在是全局对象的一个属性而不是外层闭包里的一个变量。当你把多段代码混合在一起就可能会出现问题，而事情你确实会经常这么做。<br />
总是记得加上var使你的变量的作用域处于当前的闭包和子闭包里。你当然会很乐意遵循这个这么简单的规则。<br />
如果你必须把东西放到全局对象上，你可以在浏览器上使用window.woo或者在node.js使用global.goo。</p>
<h2 style="font-weight:bold;color:#570E00;">函数与闭包（Functions and Closures）</h2>
<p>Javascript不仅仅是一系列的数据结构链。它包含了可执行和调用的代码，这种代码被称作函数。这些函数会创建链式作用域和闭包。</p>
<h3 style="font-weight:bold;color:#570E00;">观察闭包（Visualizing Closures）</h3>
<p>函数可以看作是特别的对象，对象包含了可执行的代码和属性。每个函数在定义时都会赋予一个特别的[scope]属性表明它正处于哪个环境。如果一个函数是在另外一个函数里被返回，那么对旧环境的引用就会被新的函数关闭在“闭包”里。<br />
在这个例子里我们会创建一个简单的工厂方法来产生一个闭包，并返回一个函数。</p>
<pre class="brush: javascript; gutter: true">
function makeClosure(name) {
  return function () {
    return name;
  };
}
var description1 = makeClosure("Cloe the Closure");
var description2 = makeClosure("Albert the Awesome");
console.log(description1());
console.log(description2());
</pre>
<div class="snippet">
<dl class="output">
<dt>输出</dt>
<dd>
<div class="last-expression">Cloe the Closure<br />Albert the Awesome</div>
</dd>
</dl>
</div>
<p><img src="http://www.icyfire.me/wp-content/uploads/2011/09/7857c_closure-640x340.png" alt="" title="闭包" width="640" height="340" class="alignnone size-medium wp-image-1171" /></p>
<p>当我们调用description1()的时候，VM就会查找他引用的函数然后执行它。而这个函数会在闭包的作用域里去找一个叫做name的局部变量。这是个不错的工厂方法，每个产生的函数都有自己存放局部变量的空间。</p>
<p>想深入了解闭包和它的用法，可以看<a href="http://howtonode.org/why-use-closure" target="_blank">why use closure</a>这篇文章。</p>
<h3 style="font-weight:bold;color:#570E00;">共享函数与this（Shared Functions and this）</h3>
<p>有时为了性能上的考虑，或者你纯粹喜欢这样，Javascript提供了this这个关键字让你在不同的作用域里重用函数对象，这取决于你是怎样调用它的。</p>
<p>这里我们创建了一些对象，这些对象共享了同一个函数。这个函数将会在内部引用this，向你展示它在不同的调用里会有哪些不同的表现。</p>
<pre class="brush: javascript; gutter: true">
var Lane = {
  name: "Lane the Lambda",
  description: function () {
    return this.name;
  }
};
var description = Lane.description;
var Fred = {
  description: Lane.description,
  name: "Fred the Functor"
};
// Call the function from four different scopes
console.log(Lane.description());
console.log(Fred.description());
console.log(description());
console.log(description.call({
  name: "Zed the Zetabyte"
}));
</pre>
<div class="snippet">
<dl class="output">
<dt>输出</dt>
<dd>
<div class="last-expression">Lane the Lambda<br />Fred the Functor<br />undefined<br />Zed the Zetabyte</div>
</dd>
</dl>
</div>
<p><img src="http://www.icyfire.me/wp-content/uploads/2011/09/aa776_functions.png" alt="" title="函数" width="544" height="393" class="alignnone size-full wp-image-1174" /></p>
<p>在这种图表里，我们看到就算Fred.description被设为Lane.description，它事实上只是引用那个函数。因此三个引用都是引用相同的匿名函数。因此我尽量不会用构造函数原型这个“方法”去调用函数，因为这样意味着会把这个函数绑定到构造函数以及他的“类”上（This is why I try to not call functions on constructor prototypes "methods", because that implies some sort of binding of the function to the constructor and it's "class"）。（想知道更多关于this的动态性质请看<a href="http://howtonode.org/what-is-this" target="_blank">what is this</a>）</p>
<h2 style="font-weight:bold;color:#570E00;">总结</h2>
<p>使用图表去表现这些数据结构是件很有趣的事情。我希望这个能帮助像我们一样通过视觉学习（visual learner）的人更好的掌握Javascript的语法。我具有前端设计/开发以及后台开发的经验，我希望我独特的视觉能给那些从事设计以及正在深入学习Javascript这个美妙的语言的人带来帮助。</p>
<p>(所有图表都是<a href="http://www.graphviz.org/" target="_blank">graphviz</a>的点文件（dot file），可以在<a href="http://github.com/creationix/howtonode.org/tree/master/articles/object-graphs/" target="_blank">这里</a>查看)</p>
<p>原文：<a href="http://howtonode.org/object-graphs" title="Learning Javascript with Object Graphs" target="_blank">http://howtonode.org/object-graphs</a></p>
<p>Translated by icyfire @ 2011-09-02 updated @ 2011-10-28</p>
]]></content:encoded>
			<wfw:commentRss>http://www.icyfire.me/2011/10/object-graphs-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>本地存储浅析</title>
		<link>http://www.icyfire.me/2011/10/local-storage-brief/</link>
		<comments>http://www.icyfire.me/2011/10/local-storage-brief/#comments</comments>
		<pubDate>Tue, 18 Oct 2011 11:47:25 +0000</pubDate>
		<dc:creator>icyfire</dc:creator>
				<category><![CDATA[网站前端]]></category>
		<category><![CDATA[Cookie]]></category>
		<category><![CDATA[Gears]]></category>
		<category><![CDATA[Shared Object]]></category>
		<category><![CDATA[userData]]></category>
		<category><![CDATA[Web Storage]]></category>
		<category><![CDATA[本地存储]]></category>

		<guid isPermaLink="false">http://www.icyfire.me/?p=1175</guid>
		<description><![CDATA[<img src="http://www.icyfire.me/wp-content/uploads/2011/09/20110515054811428.jpg" alt="" title="本地存储" width="600" height="202" class="alignnone size-full wp-image-1181" />

相比于桌面应用，Web应用在本地存储方面确实显得有点力不从心。在桌面应用，你可以使用INI或者XML等文件来保存配置和数据，甚至可以使用内嵌小型数据库的方法去保存数据，而对于网站来说，在很长的一段时间里，我们只能使用Cookies这个充满缺点但又无法替代的东西。不过随着互联网的发展，本地存储技术也一直在发展，但始终没有出现一个能满足需求的技术，直到Web Storage的出现。

下面我们来看下一些比较常见的本地存储技术。 <a href="http://www.icyfire.me/2011/10/local-storage-brief/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<style>
#local-storage a {text-decoration:none;}
#local-storage p, #local-storage ul {margin-bottom:18px;}
#local-storage .feature {vertical-align: middle;}
</style>
<div id="local-storage">
<img src="http://www.icyfire.me/wp-content/uploads/2011/09/20110515054811428.jpg" alt="" title="本地存储" width="600" height="202" class="alignnone size-full wp-image-1181" /></p>
<p>相比于桌面应用，Web应用在本地存储方面确实显得有点力不从心。在桌面应用，你可以使用INI或者XML等文件来保存配置和数据，甚至可以使用内嵌小型数据库的方法去保存数据，而对于网站来说，在很长的一段时间里，我们只能使用Cookies这个充满缺点但又无法替代的东西。不过随着互联网的发展，本地存储技术也一直在发展，但始终没有出现一个能满足需求的技术，直到Web Storage的出现。</p>
<p>下面我们来看下一些比较常见的本地存储技术。</p>
<h2 style="border-bottom:2px solid #487858;">Cookies</h2>
<p>这个由Netscape的前雇员Lou Montulli在1993年3月的发明的东西，至今仍然被广泛的应用在各网站上，我们用它来保存登录状态，用它来保存浏览过的商品，用它来保存购物车物品，等等。</p>
<p>目前cookie存在了以下几种的规范：</p>
<ul>
<li><a href="http://curl.haxx.se/rfc/cookie_spec.html" target="_blank">Netscape cookie草案</a>：是最早的cookie规范，也是RFC2109的基础。尽管如此，它与RFC2109还是有较大的差别，所以跟一些服务器有兼容上的问题。 </li>
<li><a href="http://www.ietf.org/rfc/rfc2109.txt" target="_blank">RFC2109</a>：基于是w3c发布的第一个官方cookie规范。理论上，所有的服务器在处理版本1的cookie时，都要遵循此规范。遗憾的是，由于这个规范过于严格，很多服务器并没有正确的实现这个标准或者还是在使用Netscape的cookie草案。</li>
<li><a href="http://www.ietf.org/rfc/rfc2965.txt" target="_blank">RFC2965</a>：cookie规范的第二个版本，指出了RFC2109里cookie版本1的不足。RFC2965的目标是最终取代RFC2109。</li>
</ul>
<p>想深入了解Cookie可以研究下这些规范，但这篇文章里并不会再深入进去，这里列出几个规范除了扫盲外主要是为了解释一个问题，什么是cookie？Netscape的cookie草案里是这么说的：</p>
<blockquote><p>A server, when returning an HTTP object to a client, may also send a piece of state information which the client will store. Included in that state object is a description of the range of URLs for which that state is valid. Any future HTTP requests made by the client which fall in that range will include a transmittal of the current value of the state object from the client back to the server. The state object is called a cookie, for no compelling reason.</p></blockquote>
<p>下面我们来看看浏览器，web服务器跟cookie之间的交互是怎样的：</p>
<ul>
<li>当我们用浏览器访问一个网站的时候，就会想服务器发起一个请求。</li>
<li>根据请求的url和cookie本身的属性，筛选出需要发送给服务器的cookie（当然也有可能没有cookie）。</li>
<li>如果有多个cookie的话，还会决定发送的顺序。</li>
<li>把这些需要发送的cookie包含在HTTP的包头里发送给服务器。</li>
<li>然后到了应答阶段，服务器会发回一个应答包头，包头里包含了cookie信息。</li>
<li>浏览器解析这个cookie，包括名称，值，路径等元素。</li>
<li>最后，把cookie保存在本地。</li>
</ul>
<p>至于哪些cookie会被发送到服务器端，是有一套规则的，例如域名选择、路径选择和Max-Age选择，这些都可以在<a href="http://www.ietf.org/rfc/rfc2109.txt" target="_blank">RFC2109</a>里找到，这里就不展开了。</p>
<p>从上面可以看到，每次的http请求，cookie都会包含在包头里发送给服务器，这也是被开发者广为诟病的一个cookie缺点，因为这意味这每个请求都无形中增加了流量，特别是像请求图片这些资源的时候，附带的cookie信息是完全没有必要的。所以现在很多网站图片等静态资源都会用独立的域名运作，这样就可以单独对这些域名进行cookie设置。<br />
除此以外，cookie还有以下影响比较大的缺点：</p>
<ul>
<li>安全性问题。cookie在http请求中是明文传递的，除非使用SSL通道，不然是不宜在cookie里放置重要信息。</li>
<li>大小问题。每个cookie的大小不能超过4K。每个Domain下cookie个数根据浏览器不同也不同。</li>
</ul>
<p>关于Cookies的一些限制问题，可以参考下Nicholas的一篇<a href="http://www.nczonline.net/blog/2008/05/17/browser-cookie-restrictions/" target="_blank">文章</a>：<br />
浏览器允许的每个域名下的Cookie数：</p>
<ul>
<li>IE7跟IE8限制为50个。</li>
<li>Firefox限制为50个。</li>
<li>Opera限制30个</li>
<li>Safari/WebKit没有限制，但是如果header的大小超过服务器能处理的情况下，则会出现错误。</li>
</ul>
<p>那如果Cookie数设置超过限制的时候，各浏览器又是如何处理呢：</p>
<ul>
<li>Safari由于没有Cookie数的限制，所以不作讨论。</li>
<li>在IE和Opera下，将会采用LRU（The Least Recently Used）方法，自动踢掉最老的cookie以腾出空间给新的cookie。IE和Opera使用这个方法。</li>
<li>Firefox就比较独特：它貌似会随机决定哪些cookie将会保留，尽管最后设置的cookie会被保留。所以在Firefox里不要超过cookie数的限制。</li>
</ul>
<p>cookie的总大小在各浏览器中也是不同的：</p>
<ul>
<li>Firefox和Safari允许cookie多达4097个字节，其中4096个字节是名字和值，1个字节是=号。</li>
<li>Opera允许cookie多达4096个字节，这些字节包含名字、值和=号。</li>
<li>IE允许4095个字节，这些字节包含名字、值和=号。</li>
</ul>
<p>注意这里用的字节，也就是，如果是多字节字符，自然就会占用两个字节。在所有浏览器里，如果设置的cookie大小超过限制，那么它就会被忽略或者不被设置。</p>
<p>从上面，我们可以看到，Cookie确实存在一些不足，但是它的一些缺点也正是它的优点，例如每个请求都会被放到包头里发送给服务器，正是这个特性我们才能很方便的传输sessionid。Cookie的出现可谓大大推动了网页的发展，而且在未来很长的一段时间里，Cookie还会继续发挥它的作用。但是也正是由于Cookie存在种种的不足，才会有新的本地存储技术出现的需求。</p>
<h2 style="border-bottom:2px solid #487858;">userData</h2>
<p>userData是微软在第一次浏览器大战中的产物，属于DHTML中的一种技术。相比起Cookie，userData在每个域名下可存储达的数据提升了不少，但是具体的大小视domain的安全域而定：</p>
<table class="mytable" cellspacing="0" style="width:100%;">
<tr>
<th scope="row" class="left top">Security Zone</th>
<th scope="col">Document Limit (KB)</th>
<th scope="col">Domain Limit (KB)</th>
</tr>
<tr>
<td class="spec">Local Machine</td>
<td>128</td>
<td>1024</td>
</tr>
<tr>
<td class="spec">Intranet</td>
<td>512</td>
<td>10240</td>
</tr>
<tr>
<td class="spec">Trusted Sites</td>
<td>128</td>
<td>1024</td>
</tr>
<tr>
<td class="spec">Internet</td>
<td>128</td>
<td>1024</td>
</tr>
<tr>
<td class="spec">Restricted</td>
<td>64</td>
<td>640</td>
</tr>
</table>
<p></p>
<p>总的来说，考虑到各种情况，最安全的做法是把文件控制在64K以下。文件的数据是XML格式，保存在系统盘的某个目录下，例如在XP下（假设C为系统盘），保存的位置为C:\Documents and Settings\用户名\UserData或C:\Documents and Settings\用户名\Application Data\Microsoft\Internet Explorer\UserData下，而在VISTA下则保存在C:\Users\用户名\AppData\Roaming\Microsoft\Internet Explorer\UserData下。</p>
<p>userData支持IE5以上的浏览器，要使用userData，必须以一个HTML元素作为宿主。也就是说，userData并不能单独使用，而必须依附于某个HTML标签上，并设置behavior：</p>
<table class="mytable" cellspacing="0" width="100%">
<tr>
<th scope="row" class="specalt top">XML</th>
<td class="top">&lt;Prefix: CustomTag ID=sID STYLE="<a href="http://msdn.microsoft.com/en-us/library/ms533503.aspx" target="_blank">behavior</a>:url('#default#userData')" /&gt; </td>
</tr>
<tr>
<th scope="row" class="specalt">HTML</th>
<td>&lt;ELEMENT STYLE="behavior:url('#default#userData')" ID=sID&gt;</td>
</tr>
<tr>
<th scope="row" rowspan="2" class="specalt">Scripting</th>
<td>object.<a href="http://msdn.microsoft.com/en-us/library/ms537842.aspx" target="_blank">style</a>.behavior = "url('#default#userData')"</td>
</tr>
<tr>
<td>object.<a href="http://msdn.microsoft.com/en-us/library/ms535922.aspx" target="_blank">addBehavior</a>("#default#userData")</td>
</tr>
</table>
<p></p>
<p>但需要注意的是并不是所有的HTML标签都能用于userData，例如绑定userData到html、head、title或者style上进行存储时就会发生错误。</p>
<p>userData的数据会一直存在，直到被删除或者到过期时间。并且基于安全的考虑，一个 userData 存储区只能用于同一目录和对同一协议进行存储。</p>
<p>跟cookie一样，userData的数据也是没有进行加密的，所以也不建议把一些重要信息保存在里面。</p>
<p>userData在数据的本地储存来说，比cookie进步了不少，但是它有个致命的缺点：仅支持IE。仅凭这一点，就注定了userData并不会有太大的作为，只能用作配合其他本地存储技术兼容低版本的IE。</p>
<p>userData具体的使用方法这里就不深入了，详情可以参阅微软的<a href="http://msdn.microsoft.com/en-us/library/ms531424.aspx" target="_blank">文档</a>。</p>
<h2 style="border-bottom:2px solid #487858;">Local Shared Object</h2>
<p>2002年，Adobe在Flash6中引入了一个新功能，并很不幸的获取了一个及具有迷惑性的名字：“Flash Cookies”。 但在Flash中，这个功能被称作Local Shared Objects或者LSO更为合适。 简单来说，这个技术允许Flash对象在每个域名上存储100KB的数据。</p>
<p>2005年，Brad Neuberg开发了一个早期的Flash到JavaScript的桥接原型接口，叫AJAX Massive Storage System(AMASS)，但是受到Flash技术的种种局限。 </p>
<p>2006年，随着Flash 8的ExternalInterface的引入，在Javascript中访问LSO变得更加简单和快速。Brad重写了AMASS并把它整合到流行的Dojo工具框架中，取名dojox.storage。同时这个技术也允许每个域名下存储100K的数据，而超过这个限制则要增加到下一个大小等级（1MB，10MB等），就会弹出提示让用户确认。</p>
<p>Adobe Flash Player不允许第三方的LSO进行跨域分享。例如，一个www.example.com的LSO不能被www.example2.com读取。然而第一方的网站可以通过专门的XML文件上的设置传送数据给第三方。</p>
<p>用户可以通过在Adobe网站上的全局存储设置面板禁用LSO，也可以右击Flash Player，在设置里对每个网站的设置进行调整。后面的方法也允许用户删除LSO。当然用户也可以手动或者借助第三方的软件来删除LSO。</p>
<p>直到版本10.1，Adobe Flash Player才支持浏览器的<a href="http://en.wikipedia.org/wiki/Privacy_mode" target="_blank">私隐模式</a>，支持的浏览器包括Chrome，Firefox，IE和Safari。</p>
<p>LSO解决了上面提到的Cookie的一些问题，例如大小，安全等。跟Cookie不同，LSO被保存为二进制文件（不过变量名具有可读性）。作为本地存储的替代方案，LSO具有了不少优点，但是缺点也是明显，就是它需要安装Flash这个插件。虽然现在Flash的普及率很高，但是这种依赖插件的技术始终不能解决问题的根源，而且为了使用这个方案，我们不得不引入额外的swf和js文件。</p>
<p>P.S. 本人极不喜欢Flash……</p>
<h2 style="border-bottom:2px solid #487858;">Gears</h2>
<p>2007年，Google启动了Gears项目。Gears是一个开源的浏览器插件，目标是为浏览器提供额外的兼容功能（例如为IE提供geolocation的API）。Gears提供了一个API用来嵌入一个基于SQLite的SQL数据库。在得到用户的允许后，Gears可以在数据库存储没有大小限制的数据。</p>
<p>Gears主要有以下特点：</p>
<table>
<tbody>
<tr>
<td class="feature"><img width="43px" height="35px" alt="Desktop" src="http://gears.google.com/images/localserver.gif"></td>
<td class="feature">让网页应用跟桌面进行更自然的交互。</td>
</tr>
<tr>
<td class="feature">
<img width="43px" height="35px" alt="Desktop" src="http://gears.google.com/images/database.gif">
</td>
<td class="feature">具有完整搜索功能数据库的本地存储。</td>
</tr>
<tr>
<td class="feature">
<img width="43px" height="35px" alt="Desktop" src="http://gears.google.com/images/workerpool.gif">
</td>
<td class="feature">在后台运行Javascript以提供性能。</td>
</tr>
</tbody>
</table>
<p></p>
<p>所以，本地存储事实上只是Gears的其中一个功能。一个嵌入式数据库对本地存储的需求来说是绰绰有余了，然而跟Flash一样，Gears只不过是一个插件，还是一个跟Flash的普及率不可相提并论的插件。而且作为一个插件，它对浏览器的支持也是不足够的，我们看看它的浏览器支持情况：</p>
<ul>
<li>Firefox 1.5-3.6</li>
<li>Internet Explorer 6.0-8.0</li>
</ul>
<p>当然造成这个状况也有有原因，就是因为Gears项目已经停止更新了。</p>
<p>2010年，Google官方宣布逐渐放弃对Gears的支持，并把工作重点转移在HTML5上……</p>
<h2 style="border-bottom:2px solid #487858;">globalStorage</h2>
<p>这是一个全局对象(globalStorage)，它维护着各种公共的或者私有的，可以用来长时期保存数据的存储空间（例如，在多重的页面和浏览器会话之间）。目前只有Firefox 2+支持。</p>
<p>globalStorage不是一个Storage实例，而是一个包含StorageObsolete实例的StorageList实例。举个栗子：</p>
<ul>
<li>globalStorage['developer.mozilla.org'] - 在developer.mozilla.org下面所有的子域都可以通过这个存储对象来进行读和写。</li>
<li>globalStorage['mozilla.org'] - 在mozilla.org域名下面的所有网页都可以通过这个存储对象来进行读和写。</li>
<li>globalStorage['org'] - 在.org域名下面的所有网页都可以通过这个存储对象来进行读和写。</li>
<li>globalStorage[] - 在任何域名下的任何网页都可以通过这个存储对象来进行读和写。</li>
</ul>
<p>Firefox 2允许访问比当前文档域名层次高的存储的对象，例如在developer.mozilla.org上你可以访问mozilla.org或者org的存储对象。但是由于安全的因素在Firefox 3以上版本中则不再允许，你只能访问当前域名的存储对象。 </p>
<h2 style="border-bottom:2px solid #487858;">Web Storage</h2>
<p>鉴于以上本地存储的方案的各种不给力，一种更强力的本地存储技术的出现貌似是很顺应潮流的事情。<a href="http://dev.w3.org/html5/webstorage/" target="_blank">Web Storage</a>被设计出来的目的就是为了提供更大，更安全，更容易使用的存储方式。</p>
<p>需要注意的一点：我们说到Web Storage总是认为它是HTML5的东西，事实上，它并不是HTML5规范的一部分，它有自己独立的一份<a href="http://dev.w3.org/html5/webstorage/" target="_blank">规范</a>。</p>
<p>Web Storage可分为local storage和session storage。local storage提供了5MB的存储空间，而sessiong storage甚至没有限制。我们来看看local storage能为我们做什么：</p>
<ul>
<li>减少网络流量</li>
<li>明显的加快显示速度</li>
<li>RPC调用时缓存数据</li>
<li>在启动时加载缓存数据（加快启动速度）</li>
<li>保存临时状态</li>
<li>应用切换时状态的恢复</li>
<li>防止网络断开时的工作的丢失</li>
</ul>
<p>local storage跟session storage除了在存储空间上不一样外，在生命周期及存储事件等特性上的表现也不一样：</p>
<table class="mytable" cellspacing="0" style="width:100%;">
<tr>
<th scope="row" class="left top">Storage<br />类型</th>
<th scope="col" width="200">大小限制</th>
<th scope="col">生命周期</th>
<th scope="col">对其他窗口和Tab的可用性</th>
<th scope="col">支持的数据类型</th>
</tr>
<tr>
<td class="spec">LocalStorage</td>
<td>每个浏览器的每个应用限制5MB。根据<a href="http://www.w3.org/TR/2009/WD-webstorage-20091222/#the-storage-interface" target="_blank">Web Storage规范</a>，用户可以根据需要增加这个限制，但是只有少数的浏览器支持。</td>
<td>保存在硬盘上直到被用户或者应用删除。</td>
<td>共享于运行同一个web应用的浏览器的所有窗口跟标签页。</td>
<td>只支持键-值对的字符串。</td>
</tr>
<tr>
<td class="spec">SessionStorage</td>
<td>只受到系统内存的限制</td>
<td>只存活于使用它的窗口或标签页</td>
<td>只能由创建它的窗口或者标签页访问</td>
<td>只支持键-值对的字符串。</td>
</tr>
</table>
<p></p>
<p>可以看出，session storage只是会话级的存储，只有同一个会话的窗口或者标签页能访问它，并且会话结束数据也会同时销毁。而local storage是一种持久化的存储，就算关闭浏览器数据依然存在，并且能在多个窗口和标签页间共享数据。</p>
<p>下面我们来看看local storage是怎样在浏览器中共享数据的：</p>
<p>每个浏览器上的每个web应用都有自己的一个LocalStorage，大小限制为5MB，并能在所有的这个浏览器上的窗口和标签页间共享。例如，假设你在Chrome上运行MyWebApp，如果你在多个标签页和窗口上运行MyWebApp，它们共享相同的大小限制为5MB的LocalStorage数据。如果你在其他浏览器打开相同的应用，例如Firefox，那么这个新的浏览器将会有它自己的LocalStorage供它上面的窗口和标签页进行共享。请看下面图片：</p>
<p><img src="http://www.icyfire.me/wp-content/uploads/2011/09/localStorage_shared.png" alt="" title="" width="622" height="439" class="alignnone size-full wp-image-1176" /></p>
<p>LocalStorage只能存储键值对字符串类型的数据，如果你想保存其他类型的数据，你只能在保存的时候把数据转化为字符串，然后在读取的时候再转化回去。就像cookie一样，LocalStorage和SessionStorage可以被诸如Chrome上的Developer Tools，Sarafi上的Web Inspector等工具检测得到。通过这些工具，用户可以移除保存的数据或者查看访问的网页保存了哪些数据。</p>
<p>LocalStorage并不是安全的存储，它保存的数据并不会进行加密，所有不宜保存一些敏感的数据。</p>
<p>Web Storage还有个重要特性就是Storage事件。当LocalStorage或者SessionStorage的数据被保存，修改或者删除的时候，当前窗口或者标签页的Storage事件就会触发。触发的Storage事件对象包含了事件发生时的storage对象，URL以及变化前后的键值。需要注意的时候，虽然规范里要求Storage事件在同一个浏览器里能被所有的窗口或者标签页触发，但是只有少数的浏览器实现了这个功能。另外，如果storage被清空了，那么事件不会包含任何被删键值对的信息。</p>
<p><img src="http://www.icyfire.me/wp-content/uploads/2011/10/localstorage_event.jpg" alt="" title="localstorage_event" width="550" height="266" class="alignnone size-full wp-image-1209" /></p>
<p>StorageEvent对象包含了以下的方法：</p>
<table class="mytable" cellspacing="0" style="width:100%;">
<tr>
<th scope="row" class="left top">方法</th>
<th scope="col">描述</th>
</tr>
<tr>
<td class="spec">getKey</td>
<td>返回被修改的键。</td>
</tr>
<tr>
<td class="spec">getNewValue</td>
<td>返回被修改后的键值，如果值没有修改或者调用的是Storage.clear()的话，则返回null。</td>
</tr>
<tr>
<td class="spec">getOldValue</td>
<td>返回被修改前的键值，如果值没有修改或者调用的是Storage.clear()的话，则返回null。</td>
</tr>
<tr>
<td class="spec">getStorageArea</td>
<td>返回触发事件的SessionStorage或者LocalStorage对象。</td>
</tr>
<tr>
<td class="spec">getURL</td>
<td>触发当前存储事件的页面的url。</td>
</tr>
</table>
<p></p>
<p>目前支持Web Storage的浏览器如下：</p>
<p><img src="http://www.icyfire.me/wp-content/uploads/2011/10/localstorage_support.jpg" alt="" title="localstorage_support" width="640" height="55" class="alignnone size-full wp-image-1208" /></p>
<h2 style="border-bottom:2px solid #487858;">总结</h2>
<p>可以看到，本地存储一直在发展着，特别是HTML5阶段的Web Storage，已经是一个比较完善的实现。但是，HTML5的普及还遥遥无期，只有比较新的浏览器才支持Web Storage，而有的就算支持Web Storage也不完全支持Storage事件，应此，为了兼容大部分的浏览器，就必须协同其他的本地存储技术一起使用，例如对不支持Web Storage的浏览器，譬如IE6和IE7则使用userData，低版本的Firefox则使用globalStorage。目前已经有不少的js库去实现这个功能，例如：<a href="http://codecto.com/2011/07/localstorage-cross-browser-store-js/" target="_blank">store.js</a>， <a href="https://github.com/hugeinc/USTORE.js" target="_blank">USTORE.js</a>， <a href="https://github.com/kbjr/Box.js/blob/master/box.js" target="_blank">Box.js</a>等等。</p>
<p>参考资料：<br />
<a href="http://hc.apache.org/httpclient-3.x/cookies.html" target="_blank">http://hc.apache.org/httpclient-3.x/cookies.html</a><br />
<a href="http://www.nczonline.net/blog/2008/05/17/browser-cookie-restrictions/" target="_blank">http://www.nczonline.net/blog/2008/05/17/browser-cookie-restrictions/</a><br />
<a href="http://msdn.microsoft.com/en-us/library/ms531424.aspx" target="_blank">http://msdn.microsoft.com/en-us/library/ms531424.aspx</a><br />
<a href="http://shop.oreilly.com/product/9780596806033.do" target="_blank">HTML5: Up and Running</a><br />
<a href="http://en.wikipedia.org/wiki/Local_Shared_Object" target="_blank">http://en.wikipedia.org/wiki/Local_Shared_Object</a><br />
<a href="http://gears.google.com/" target="_blank">http://gears.google.com/</a><br />
<a href="https://developer.mozilla.org/cn/DOM/Storage" target="_blank">https://developer.mozilla.org/cn/DOM/Storage</a><br />
<a href="http://code.google.com/intl/zh-CN/webtoolkit/doc/latest/DevGuideHtml5Storage.html" target="_blank">http://code.google.com/intl/zh-CN/webtoolkit/doc/latest/DevGuideHtml5Storage.html</a><br />
<a href="http://dev.opera.com/articles/view/web-storage/" target="_blank">http://dev.opera.com/articles/view/web-storage/</a><br />
<a href="https://developer.mozilla.org/en/DOM/Storage" target="_blank">https://developer.mozilla.org/en/DOM/Storage</a><br />
<a href="http://sixrevisions.com/html/introduction-web-storage/" target="_blank">http://sixrevisions.com/html/introduction-web-storage/</a>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.icyfire.me/2011/10/local-storage-brief/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MongoDB与内存</title>
		<link>http://www.icyfire.me/2011/08/mongodb-and-memroy/</link>
		<comments>http://www.icyfire.me/2011/08/mongodb-and-memroy/#comments</comments>
		<pubDate>Sun, 21 Aug 2011 12:44:28 +0000</pubDate>
		<dc:creator>icyfire</dc:creator>
				<category><![CDATA[网站前端]]></category>
		<category><![CDATA[MongoDB]]></category>
		<category><![CDATA[NoSQL]]></category>

		<guid isPermaLink="false">http://www.icyfire.me/?p=1157</guid>
		<description><![CDATA[但凡初次接触MongoDB的人，无不惊讶于它对内存的贪得无厌，至于个中缘由，我先讲讲Linux是如何管理内存的，再说说MongoDB是如何使用内存的，答案自然就清楚了。

<img src="http://www.icyfire.me/wp-content/uploads/2011/08/79_110607152750_1-640x213.png" alt="" title="79_110607152750_1" width="640" height="213" class="aligncenter size-medium wp-image-1158" /> <a href="http://www.icyfire.me/2011/08/mongodb-and-memroy/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>但凡初次接触MongoDB的人，无不惊讶于它对内存的贪得无厌，至于个中缘由，我先讲讲Linux是如何管理内存的，再说说MongoDB是如何使用内存的，答案自然就清楚了。</p>
<p>据说带着问题学习更有效，那就先看一个MongoDB服务器的top命令结果：</p>
<pre class="brush: shell; gutter: true">shell&gt; top -p $(pidof mongod)
Mem:  32872124k total, 30065320k used,  2806804k free,   245020k buffers
Swap:  2097144k total,      100k used,  2097044k free, 26482048k cached

 VIRT  RES  SHR %MEM
1892g  21g  21g 69.6</pre>
<p>这台MongoDB服务器有没有性能问题？大家可以一边思考一边继续阅读。</p>
<h3>先讲讲Linux是如何管理内存的</h3>
<p>在Linux里（别的系统也差不多），内存有物理内存和<a href="http://en.wikipedia.org/wiki/Virtual_memory" target="_blank">虚拟内存</a>之说，物理内存是什么自然无需解释，虚拟内存实际是物理内存的抽象，多数情况下，出于方便性的考虑，程序访问的都是虚拟内存地址，然后操作系统会把它翻译成物理内存地址。</p>
<p>很多人会把虚拟内存和Swap混为一谈，实际上Swap只是虚拟内存引申出的一种技术而已：操作系统一旦物理内存不足，为了腾出内存空间存放新内容，就会把当前物理内存中的内容放到交换分区里，稍后用到的时候再取回来，需要注意的是，Swap的使用可能会带来性能问题，偶尔为之无需紧张，糟糕的是物理内存和交换分区频繁的发生数据交换，这被称之为Swap颠簸，一旦发生这种情况，先要明确是什么原因造成的，如果是内存不足就好办了，加内存就可以解决，不过有的时候即使内存充足也可能会出现这种问题，比如MySQL就有可能出现这样的情况，解决方法是限制使用Swap：</p>
<pre class="brush: shell; gutter: true">shell&gt; sysctl -w vm.swappiness=0</pre>
<p>查看内存情况最常用的是free命令：</p>
<pre class="brush: shell; gutter: true">shell&gt; free -m
             total       used       free     shared    buffers     cached
Mem:         32101      29377       2723          0        239      25880
-/+ buffers/cache:       3258      28842
Swap:         2047          0       2047</pre>
<p>新手看到used一栏数值偏大，free一栏数值偏小，往往会认为内存要用光了。其实并非如此，之所以这样是因为每当我们操作文件的时候，Linux都会尽可能的把文件缓存到内存里，这样下次访问的时候，就可以直接从内存中取结果，所以cached一栏的数值非常的大，不过不用担心，这部分内存是可回收的，操作系统会按照<a href="http://en.wikipedia.org/wiki/Cache_algorithms" target="_blank">LRU</a>算法淘汰冷数据。还有一个buffers，也是可回收的，不过它是保留给块设备使用的。</p>
<p>知道了原理，我们就可以推算出系统可用的内存是free + buffers + cached：</p>
<pre class="brush: shell; gutter: true">shell&gt; echo "29377 - 239 - 25880" | bc -l
3258</pre>
<p>除了free命令，还可以使用sar命令：</p>
<pre class="brush: shell; gutter: true">shell&gt; sar -r
kbmemfree kbmemused  %memused kbbuffers  kbcached
  3224392  29647732     90.19    246116  26070160

shell&gt; sar -W
pswpin/s pswpout/s
    0.00      0.00</pre>
<p>希望你没有被%memused吓到，如果不幸言中，重读本文。</p>
<h3>再说说MongoDB是如何使用内存的</h3>
<p>目前，MongoDB使用的是<a href="http://www.mongodb.org/display/DOCS/Caching" target="_blank">内存映射存储引擎</a>，它会把磁盘IO操作转换成内存操作，如果是读操作，内存中的数据起到缓存的作用，如果是写操作，内存还可以把随机的写操作转换成顺序的写操作，总之可以大幅度提升性能。MongoDB并不干涉内存管理工作，而是把这些工作留给操作系统的虚拟内存管理器去处理，这样的好处是简化了MongoDB的工作，但坏处是你没有方法很方便的控制MongoDB占多大内存，事实上MongoDB会占用所有能用的内存，所以最好不要把别的服务和MongoDB放一起。</p>
<p>有时候，即便MongoDB使用的是64位操作系统，也可能会遭遇臭名昭著的<a href="http://en.wikipedia.org/wiki/Out_of_memory" target="_blank">OOM</a>问题，出现这种情况，多半是因为限制了虚拟内存的大小所致，可以这样查看当前值：</p>
<pre class="brush: shell; gutter: true">shell&gt; ulimit -a | grep 'virtual'</pre>
<p>多数操作系统缺省都是把它设置成unlimited的，如果你的操作系统不是，可以这样修改：</p>
<pre class="brush: shell; gutter: true">shell&gt; ulimit -v unlimited</pre>
<p>有时候，MongoDB连接数过多的话，也可能影响性能，连接数可以这样查询：</p>
<pre class="brush: shell; gutter: true">mongo&gt; db.serverStatus().connections</pre>
<p>每个连接都是一个线程，需要一个Stack，而Linux下缺省的Stack设置一般比较大：</p>
<pre class="brush: shell; gutter: true"># ulimit -a | grep stack
stack size              (kbytes, -s) 10240</pre>
<p>所有连接消耗的内存加起来会相当惊人，推荐把Stack设置小一点，比如说1024：</p>
<pre class="brush: shell; gutter: true">shell&gt; ulimit -s 1024</pre>
<p>注：ulimit的使用是有上下文的，最好放在MongoDB的启动脚本里。</p>
<p>有时候，出于某些原因，你可能想释放掉MongoDB占用的内存，不过前面说了，内存管理工作是由虚拟内存管理器控制的，所以通常你只能通过重启服务来释放内存，你一定不齿于这样的方法，幸好可以使用MongoDB内置的<a href="http://www.mongodb.org/display/DOCS/List+of+Database+Commands" target="_blank">closeAllDatabases</a>命令达到目的：</p>
<pre class="brush: shell; gutter: true">mongo&gt; use admin
mongo&gt; db.runCommand({closeAllDatabases:1})</pre>
<p>另外，通过调整内核参数drop_caches也可以释放缓存：</p>
<pre class="brush: shell; gutter: true">shell&gt; sysctl -w vm.drop_caches=1</pre>
<p>平时可以通过mongo命令行来监控MongoDB的内存使用情况，如下所示：</p>
<pre class="brush: shell; gutter: true">mongo&gt; db.serverStatus().mem:
{
    "resident" : 22346,
    "virtual" : 1938524,
    "mapped" : 962283
}</pre>
<p>还可以通过mongostat命令来监控MongoDB的内存使用情况，如下所示：</p>
<pre class="brush: shell; gutter: true">shell&gt; mongostat
mapped  vsize    res faults
  940g  1893g  21.9g      0</pre>
<p>其中内存相关字段的含义是：</p>
<ul>
<li>mapped：映射到内存的数据大小</li>
<li>visze：占用的虚拟内存大小</li>
<li>res：占用的物理内存大小</li>
</ul>
<p>注：如果操作不能在内存中完成，结果faults列的数值不会是0，视大小可能有性能问题。</p>
<p>在上面的结果中，vsize是mapped的两倍，而mapped等于数据文件的大小，所以说vsize是数据文件的两倍，之所以会这样，是因为本例中，MongoDB开启了<a href="http://www.mongodb.org/display/DOCS/Journaling" target="_blank">journal</a>，需要在内存里多映射一次数据文件，如果关闭journal，则vsize和mapped大致相当。</p>
<p>如果想验证这一点，可以在开启或关闭journal后，通过pmap命令来观察文件映射情况：</p>
<pre class="brush: shell; gutter: true">shell&gt; pmap $(pidof mongod)</pre>
<p>到底MongoDB配备多大内存合适？宽泛点来说，多多益善，如果要确切点来说，这实际取决于你的数据及索引的大小，内存如果能够装下全部数据加索引是最佳情况，不过很多时候，数据都会比内存大，比如本文所涉及的MongoDB实例：</p>
<pre class="brush: shell; gutter: true">mongo&gt; db.stats()
{
    "dataSize" : 1004862191980,
    "indexSize" : 1335929664
}</pre>
<p>本例中索引只有1G多，内存完全能装下，而数据文件则达到了1T，估计很难找到这么大内存，此时保证内存能装下热数据即可，至于热数据是多少，取决于具体的应用。如此一来内存大小就明确了：内存 > 索引 + 热数据，最好有点富余，因为前面提到过，连接本身也要消耗一定的内存，另外，操作系统本身正常运转也需要消耗一部分内存。</p>
<p>关于MongoDB与内存的话题，大家还可以参考<a href="http://www.mongodb.org/display/DOCS/Checking+Server+Memory+Usage" target="_blank">官方文档</a>中的相关介绍。</p>
<p>原文：<a href="http://huoding.com/2011/08/19/107" target="_blank">MongoDB与内存</a><br />
作者：<a href="http://huoding.com/author/laowang" target="_blank">老王</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.icyfire.me/2011/08/mongodb-and-memroy/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>一致性哈希算法及其在分布式系统中的应用</title>
		<link>http://www.icyfire.me/2011/08/consistent-hash-intro/</link>
		<comments>http://www.icyfire.me/2011/08/consistent-hash-intro/#comments</comments>
		<pubDate>Thu, 11 Aug 2011 12:39:04 +0000</pubDate>
		<dc:creator>icyfire</dc:creator>
				<category><![CDATA[网站前端]]></category>
		<category><![CDATA[Memcached]]></category>
		<category><![CDATA[NoSQL]]></category>

		<guid isPermaLink="false">http://www.icyfire.me/?p=1147</guid>
		<description><![CDATA[<img src="http://www.icyfire.me/wp-content/uploads/2011/08/consistent-hash-intro-00.png" alt="" title="" width="538" height="346" class="aligncenter size-full wp-image-1148" />

本文将会从实际应用场景出发，介绍一致性哈希算法（Consistent Hash）及其在分布式系统中的应用。首先本文会描述一个在日常开发中经常会遇到的问题场景，借此介绍一致性哈希算法以及这个算法如何解决此问题；接下来会对这个算法进行相对详细的描述，并讨论一些如虚拟节点等与此算法应用相关的话题。 <a href="http://www.icyfire.me/2011/08/consistent-hash-intro/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<h1>摘要</h1>
<p>本文将会从实际应用场景出发，介绍一致性哈希算法（Consistent Hash）及其在分布式系统中的应用。首先本文会描述一个在日常开发中经常会遇到的问题场景，借此介绍一致性哈希算法以及这个算法如何解决此问题；接下来会对这个算法进行相对详细的描述，并讨论一些如虚拟节点等与此算法应用相关的话题。</p>
<h1>分布式缓存问题</h1>
<p>假设我们有一个网站，最近发现随着流量增加，服务器压力越来越大，之前直接读写数据库的方式不太给力了，于是我们想引入Memcached作为缓存机制。现在我们一共有三台机器可以作为Memcached服务器，如下图所示。</p>
<p><img src="http://www.icyfire.me/wp-content/uploads/2011/08/consistent-hash-intro-00.png" alt="" title="" width="538" height="346" class="aligncenter size-full wp-image-1148" /></p>
<p>很显然，最简单的策略是将每一次Memcached请求随机发送到一台Memcached服务器，但是这种策略可能会带来两个问题：一是同一份数据可能被存在不同的机器上而造成数据冗余，二是有可能某数据已经被缓存但是访问却没有命中，因为无法保证对相同key的所有访问都被发送到相同的服务器。因此，随机策略无论是时间效率还是空间效率都非常不好。</p>
<p>要解决上述问题只需做到如下一点：保证对相同key的访问会被发送到相同的服务器。很多方法可以实现这一点，最常用的方法是计算哈希。例如对于每次访问，可以按如下算法计算其哈希值：</p>
<p>h = Hash(key) % 3</p>
<p>其中Hash是一个从字符串到正整数的哈希映射函数。这样，如果我们将Memcached Server分别编号为0、1、2，那么就可以根据上式和key计算出服务器编号h，然后去访问。</p>
<p>这个方法虽然解决了上面提到的两个问题，但是存在一些其它的问题。如果将上述方法抽象，可以认为通过：</p>
<p>h = Hash(key) % N</p>
<p>这个算式计算每个key的请求应该被发送到哪台服务器，其中N为服务器的台数，并且服务器按照0 – (N-1)编号。</p>
<p>这个算法的问题在于容错性和扩展性不好。所谓容错性是指当系统中某一个或几个服务器变得不可用时，整个系统是否可以正确高效运行；而扩展性是指当加入新的服务器后，整个系统是否可以正确高效运行。</p>
<p>现假设有一台服务器宕机了，那么为了填补空缺，要将宕机的服务器从编号列表中移除，后面的服务器按顺序前移一位并将其编号值减一，此时每个key就要按h = Hash(key) % (N-1)重新计算；同样，如果新增了一台服务器，虽然原有服务器编号不用改变，但是要按h = Hash(key) % (N+1)重新计算哈希值。因此系统中一旦有服务器变更，大量的key会被重定位到不同的服务器从而造成大量的缓存不命中。而这种情况在分布式系统中是非常糟糕的。</p>
<p>一个设计良好的分布式哈希方案应该具有良好的单调性，即服务节点的增减不会造成大量哈希重定位。一致性哈希算法就是这样一种哈希方案。</p>
<h1>一致性哈希算法</h1>
<h2>算法简述</h2>
<p>一致性哈希算法（Consistent Hash）最早在论文《<a href="http://www.akamai.com/dl/technical_publications/ConsistenHashingandRandomTreesDistributedCachingprotocolsforrelievingHotSpotsontheworldwideweb.pdf" target="_blank">Consistent Hashing and Random Trees: Distributed Caching Protocols for Relieving Hot Spots on the World Wide Web</a>》中被提出。简单来说，一致性哈希将整个哈希值空间组织成一个虚拟的圆环，如假设某哈希函数H的值空间为0 - 2<sup>32</sup>-1（即哈希值是一个32位无符号整形），整个哈希空间环如下：</p>
<p><img src="http://www.icyfire.me/wp-content/uploads/2011/08/consistent-hash-intro-01.png" alt="" title="" width="229" height="246" class="aligncenter size-full wp-image-1149" /></p>
<p>整个空间按顺时针方向组织。0和2<sup>32</sup>-1在零点中方向重合。</p>
<p>下一步将各个服务器使用H进行一个哈希，具体可以选择服务器的ip或主机名作为关键字进行哈希，这样每台机器就能确定其在哈希环上的位置，这里假设将上文中三台服务器使用ip地址哈希后在环空间的位置如下：</p>
<p><img src="http://www.icyfire.me/wp-content/uploads/2011/08/consistent-hash-intro-02.png" alt="" title="" width="298" height="248" class="aligncenter size-full wp-image-1150" /></p>
<p>接下来使用如下算法定位数据访问到相应服务器：将数据key使用相同的函数H计算出哈希值h，通根据h确定此数据在环上的位置，从此位置沿环顺时针“行走”，第一台遇到的服务器就是其应该定位到的服务器。</p>
<p>例如我们有A、B、C、D四个数据对象，经过哈希计算后，在环空间上的位置如下：<br />
<img src="http://www.icyfire.me/wp-content/uploads/2011/08/consistent-hash-intro-03.png" alt="" title="" width="299" height="259" class="aligncenter size-full wp-image-1151" /></p>
<p>根据一致性哈希算法，数据A会被定为到Server 1上，D被定为到Server 3上，而B、C分别被定为到Server 2上。</p>
<h2>容错性与可扩展性分析</h2>
<p>下面分析一致性哈希算法的容错性和可扩展性。现假设Server 3宕机了：</p>
<p><img src="http://www.icyfire.me/wp-content/uploads/2011/08/consistent-hash-intro-04.png" alt="" title="" width="299" height="259" class="aligncenter size-full wp-image-1152" /></p>
<p>可以看到此时A、C、B不会受到影响，只有D节点被重定位到Server 2。一般的，在一致性哈希算法中，如果一台服务器不可用，则受影响的数据仅仅是此服务器到其环空间中前一台服务器（即顺着逆时针方向行走遇到的第一台服务器）之间数据，其它不会受到影响。</p>
<p>下面考虑另外一种情况，如果我们在系统中增加一台服务器Memcached Server 4：</p>
<p><img src="http://www.icyfire.me/wp-content/uploads/2011/08/consistent-hash-intro-05.png" alt="" title="" width="299" height="259" class="aligncenter size-full wp-image-1153" /></p>
<p>此时A、D、C不受影响，只有B需要重定位到新的Server 4。一般的，在一致性哈希算法中，如果增加一台服务器，则受影响的数据仅仅是新服务器到其环空间中前一台服务器（即顺着逆时针方向行走遇到的第一台服务器）之间数据，其它不会受到影响。</p>
<p>综上所述，一致性哈希算法对于节点的增减都只需重定位环空间中的一小部分数据，具有较好的容错性和可扩展性。</p>
<h2>虚拟节点</h2>
<p>一致性哈希算法在服务节点太少时，容易因为节点分部不均匀而造成数据倾斜问题。例如我们的系统中有两台服务器，其环分布如下：</p>
<p><img src="http://www.icyfire.me/wp-content/uploads/2011/08/consistent-hash-intro-06.png" alt="" title="" width="285" height="246" class="aligncenter size-full wp-image-1154" /></p>
<p>此时必然造成大量数据集中到Server 1上，而只有极少量会定位到Server 2上。为了解决这种数据倾斜问题，一致性哈希算法引入了虚拟节点机制，即对每一个服务节点计算多个哈希，每个计算结果位置都放置一个此服务节点，称为虚拟节点。具体做法可以在服务器ip或主机名的后面增加编号来实现。例如上面的情况，我们决定为每台服务器计算三个虚拟节点，于是可以分别计算“Memcached Server 1#1”、“Memcached Server 1#2”、“Memcached Server 1#3”、“Memcached Server 2#1”、“Memcached Server 2#2”、“Memcached Server 2#3”的哈希值，于是形成六个虚拟节点：</p>
<p><img src="http://www.icyfire.me/wp-content/uploads/2011/08/consistent-hash-intro-07.png" alt="" title="" width="341" height="265" class="aligncenter size-full wp-image-1155" /></p>
<p>同时数据定位算法不变，只是多了一步虚拟节点到实际节点的映射，例如定位到“Memcached Server 1#1”、“Memcached Server 1#2”、“Memcached Server 1#3”三个虚拟节点的数据均定位到Server 1上。这样就解决了服务节点少时数据倾斜的问题。在实际应用中，通常将虚拟节点数设置为32甚至更大，因此即使很少的服务节点也能做到相对均匀的数据分布。</p>
<h1>总结</h1>
<p>目前一致性哈希基本成为了分布式系统组件的标准配置，例如Memcached的各种客户端都提供内置的一致性哈希支持。本文只是简要介绍了这个算法，更深入的内容可以参看论文《<a href="http://www.akamai.com/dl/technical_publications/ConsistenHashingandRandomTreesDistributedCachingprotocolsforrelievingHotSpotsontheworldwideweb.pdf" target="_blank">Consistent Hashing and Random Trees: Distributed Caching Protocols for Relieving Hot Spots on the World Wide Web</a>》，同时提供一个<a href="http://www.codeproject.com/KB/recipes/lib-conhash.aspx" target="_blank">C语言版本的实现</a>供参考。</p>
<p>原文:<a href="http://www.cnblogs.com/leoo2sk/archive/2011/08/11/consistent-hash-intro.html" target="_blank">http://www.cnblogs.com/leoo2sk/archive/2011/08/11/consistent-hash-intro.html</a><br />
作者:<a href="http://leoo2sk.cnblogs.com/" target="_blank">张洋</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.icyfire.me/2011/08/consistent-hash-intro/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[404]css-tricks.com</title>
		<link>http://www.icyfire.me/2011/01/404-css-tricks/</link>
		<comments>http://www.icyfire.me/2011/01/404-css-tricks/#comments</comments>
		<pubDate>Thu, 13 Jan 2011 10:36:52 +0000</pubDate>
		<dc:creator>icyfire</dc:creator>
				<category><![CDATA[网站前端]]></category>

		<guid isPermaLink="false">http://www.icyfire.me/?p=1021</guid>
		<description><![CDATA[css-tricks.com的404页面。传说中的"爆code"，呵呵。]]></description>
			<content:encoded><![CDATA[<p><a href="http://css-tricks.com/-" target="_blank"><img src="http://www.icyfire.me/wp-content/uploads/2011/01/404.css-tricks.com_.jpg" alt="" title="css-tricks.com" width="570" height="380" class="aligncenter size-full wp-image-1022" /></a></p>
<p><a href="http://css-tricks.com" target="_blank">css-tricks.com</a>的404页面。传说中的"爆code"，呵呵。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.icyfire.me/2011/01/404-css-tricks/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>1024字节javascript写成的3D圣诞树</title>
		<link>http://www.icyfire.me/2010/12/how-i-did-the-1kb-christmas-tree/</link>
		<comments>http://www.icyfire.me/2010/12/how-i-did-the-1kb-christmas-tree/#comments</comments>
		<pubDate>Fri, 17 Dec 2010 15:53:52 +0000</pubDate>
		<dc:creator>icyfire</dc:creator>
				<category><![CDATA[网站前端]]></category>
		<category><![CDATA[Javascript]]></category>

		<guid isPermaLink="false">http://www.icyfire.me/?p=1007</guid>
		<description><![CDATA[<a href="http://js1k.com/2010-xmas/demo/856" target="_blank"><img src="http://www.icyfire.me/wp-content/uploads/2010/12/2010-12-17-21-51-07.gif" alt="" title="2010-12-17 21-51-07" width="451" height="347" class="aligncenter size-full wp-image-1008" /></a>

请点击上面的图片查看<a href="http://js1k.com/2010-xmas/demo/856" target="_blank">Demo</a>，或者把下面的代码保存为html文件用浏览器里打开。
由于用到canvas以及一些复杂的运算，建议使用Chrome浏览器观看，最为流畅，其次是Opera 11（已经开始有点卡了），Firefox3.6差不多是逐帧播放了，Safari 5貌似有bug，除非用鼠标不断点击，不然几乎不会动（以上结果均出自我的性能低下的小本子）。用IE的话请自重。

预祝全宇宙生物剩蛋快乐。 <a href="http://www.icyfire.me/2010/12/how-i-did-the-1kb-christmas-tree/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://js1k.com/2010-xmas/demo/856" target="_blank"><img src="http://www.icyfire.me/wp-content/uploads/2010/12/2010-12-17-21-51-07.gif" alt="" title="2010-12-17 21-51-07" width="451" height="347" class="aligncenter size-full wp-image-1008" /></a></p>
<p>请点击上面的图片查看<a href="http://js1k.com/2010-xmas/demo/856" target="_blank">Demo</a>，或者把下面的代码保存为html文件用浏览器里打开。<br />
由于用到canvas以及一些复杂的运算，建议使用Chrome浏览器观看，最为流畅，其次是Opera 11（已经开始有点卡了），Firefox3.6差不多是逐帧播放了，Safari 5貌似有bug，除非用鼠标不断点击，不然几乎不会动（以上结果均出自我的性能低下的小本子）。用IE的话请自重。</p>
<p>预祝全宇宙生物剩蛋快乐。</p>
<pre lang="html4strict">
<!doctype html>
<html>
    <head>

        <meta charset="utf-8" />
    </head>
    <body>
        <canvas id="c"></canvas>
        <script>
            var b = document.body;
            var c = document.getElementsByTagName('canvas')[0];
            var a = c.getContext('2d');
            document.body.clientWidth; // fix bug in chrome.
        </script>
        <script>
        // start of submission //
        M=Math;Q=M.random;J=[];U=16;T=M.sin;E=M.sqrt;for(O=k=0;x=z=j=i=k<200;)with(M[k]=k?c.cloneNode(0):c){width=height=k?32:W=446;with(getContext('2d'))if(k>10|!k)for(font='60px Impact',V='rgba(';I=i*U,fillStyle=k?k==13?V+'205,205,215,.15)':V+(147+I)+','+(k%2?128+I:0)+','+I+',.5)':'%23cca',i<7;)beginPath(fill(arc(U-i/3,24-i/2,k==13?4-(i++)/2:8-i++,0,M.PI*2,1)));else for(;x=T(i),y=Q()*2-1,D=x*x+y*y,B=E(D-x/.9-1.5*y+1),R=67*(B+1)*(L=k/9+.8)>>1,i++<W;)if(D<1)beginPath(strokeStyle=V+R+','+(R+B*L>>0)+',40,.1)'),moveTo(U+x*8,U+y*8),lineTo(U+x*U,U+y*U),stroke();for(y=H=k+E(k++)*25,R=Q()*W;P=3,j<H;)J[O++]=[x+=T(R)*P+Q()*6-3,y+=Q()*U-8,z+=T(R-11)*P+Q()*6-3,j/H*20+((j+=U)>H&#038;Q()>.8?Q(P=9)*4:0)>>1]}setInterval(function G(m,l){A=T(D-11);if(l)return(m[2]-l[2])*A+(l[0]-m[0])*T(D);a.clearRect(0,0,W,W);J.sort(G);for(i=0;L=J[i++];a.drawImage(M[L[3]+1],207+L[0]*A+L[2]*T(D)>>0,L[1]>>1)){if(i==2e3)a.fillText('Merry Xmas!',U,345);if(!(i%7))a.drawImage(M[13],((157*(i*i)+T(D*5+i*i)*5)%W)>>0,((113*i+(D*i)/60)%(290+i/99))>>0);}D+=.02},1)
        // end of submission //
        </script>
    </body>
</html>
</pre>
<p>作者<a href="http://www.romancortes.com/blog/how-i-did-the-1kb-christmas-tree/" target="_blank">原文</a>里有详细的原理解析。</p>
<p><img src="http://www.icyfire.me/wp-content/uploads/2010/12/arbol_1.gif" alt="" title="arbol_1" width="374" height="168" class="aligncenter size-full wp-image-1009" /></p>
<p><img src="http://www.icyfire.me/wp-content/uploads/2010/12/arbol_2.gif" alt="" title="arbol_2" width="374" height="168" class="aligncenter size-full wp-image-1010" /></p>
<p><img src="http://www.icyfire.me/wp-content/uploads/2010/12/arbol_3.gif" alt="" title="arbol_3" width="318" height="162" class="aligncenter size-full wp-image-1011" /></p>
<p><img src="http://www.icyfire.me/wp-content/uploads/2010/12/arbol_4.gif" alt="" title="arbol_4" width="480" height="276" class="aligncenter size-full wp-image-1012" /></p>
<p><img src="http://www.icyfire.me/wp-content/uploads/2010/12/arbol_5.gif" alt="" title="arbol_5" width="282" height="368" class="aligncenter size-full wp-image-1013" /></p>
<p><img src="http://www.icyfire.me/wp-content/uploads/2010/12/arbol_6.gif" alt="" title="arbol_6" width="351" height="171" class="aligncenter size-full wp-image-1014" /></p>
<p>源文：<a href="http://www.romancortes.com/blog/how-i-did-the-1kb-christmas-tree/">How I did the 1kb Christmas Tree</a><br />
作者：<a href="http://www.romancortes.com">romancortes</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.icyfire.me/2010/12/how-i-did-the-1kb-christmas-tree/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[翻译]Data URI浅析</title>
		<link>http://www.icyfire.me/2010/08/data-uris-explained/</link>
		<comments>http://www.icyfire.me/2010/08/data-uris-explained/#comments</comments>
		<pubDate>Thu, 05 Aug 2010 12:45:46 +0000</pubDate>
		<dc:creator>icyfire</dc:creator>
				<category><![CDATA[网站前端]]></category>
		<category><![CDATA[Data URI]]></category>

		<guid isPermaLink="false">http://www.icyfire.me/?p=958</guid>
		<description><![CDATA[<img src="http://www.icyfire.me/wp-content/uploads/2010/08/data-uris-explained.jpg" alt="" title="data-uris-explained" width="520" height="185" class="alignnone size-full wp-image-1212" />

Nicholas C. Zakas去年的一篇关于Data URI的文章。
<blockquote>在最近的印象中，最受期待的浏览器功能之一就是data URI了。最近已经有不少关于data URI的文章：我同事Stoyan Stefanov已经写了<a href="http://phpied.com/data-urls-what-are-they-and-how-to-use" target="_blank">两篇</a>关于data URI的<a href="http://www.phpied.com/mhtml-when-you-need-data-uris-in-ie7-and-under/" target="_blank">文章</a>，我旧同事Hedger Wang也写了一篇关于如何在IE使用data URI的<a href="http://www.hedgerwow.com/360/dhtml/base64-image/demo.php" target="_blank">文章</a>。但出乎意料的是，对于data URI的误解和困惑依然屡见不鲜。它是什么？它是怎么工作的？为什么你会想去使用它？</blockquote> <a href="http://www.icyfire.me/2010/08/data-uris-explained/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.icyfire.me/wp-content/uploads/2010/08/data-uris-explained.jpg" alt="" title="data-uris-explained" width="520" height="185" class="alignnone size-full wp-image-1212" /></p>
<p>在最近的印象中，最受期待的浏览器功能之一就是data URI了。最近已经有不少关于data URI的文章：我同事Stoyan Stefanov已经写了<a href="http://phpied.com/data-urls-what-are-they-and-how-to-use" target="_blank">两篇</a>关于data URI的<a href="http://www.phpied.com/mhtml-when-you-need-data-uris-in-ie7-and-under/" target="_blank">文章</a>，我旧同事Hedger Wang也写了一篇关于如何在IE使用data URI的<a href="http://www.hedgerwow.com/360/dhtml/base64-image/demo.php" target="_blank">文章</a>。但出乎意料的是，对于data URI的误解和困惑依然屡见不鲜。它是什么？它是怎么工作的？为什么你会想去使用它？</p>
<h3>是URI，不是URL</h3>
<p>URL是uniform resource locator的缩写，是一个协议（用什么方式去获取数据）和给定资源的存放地址的组合。每一个公开可访问的资源，例如图片，JS文件，HTML文件或者样式表文件，都有一个URL告诉浏览器从哪里下载它们。浏览器会根据这个URL建立一个链接，并开始下载或执行这个文件。</p>
<p>URL其实也是个URI，URI是uniform resource identifier的缩写。URI指定了一个协议用来接收信息，包括一些关于资源的额外的信息。那些额外的信息可能是一个地址也可能不是（如果是的话，那么URI就是URL了），但是它总是跟一个特定的协议和有关联。因此，既然不包含地址信息，data URI也就不是URL了。</p>
<h3>Data URI的格式</h3>
<p>data URI的格式很简单，在<a href="http://tools.ietf.org/html/rfc2397" target="_blank">RFC 2397</a>里有清楚的说明（内容很短，你可以把它全部看完）。基本的格式如下：</p>
<pre class="brush:text;gutter:false;">
data:[&lt;mime type&gt;][;charset=&lt;charset&gt;][;base64],&lt;encoded data&gt;
</pre>
<p>在这个格式中，data：是URI的协议，表明这是一个data URI。第二部分，MIME type，表明了要呈现的数据的类型。拿PNG图片举个例子，它的MIME type是image/png。如果没有指定，MIME type将会默认为text/plain。charset在大多数情况下可以无视，对于图片来说它根本没用。下一部分指明了使用的编码。没必要跟随潮流，你不一定要用base 64编码。如果内容不是用base 64进行编码，那么这些数据就会使用标准的URL编码（对URL安全的ASCII字符将会保留原样显示，其他会显示成%xx格式的十六进制编码）进行编码。编码后的数据可能会包含一些没用空格，这些空格被认为没啥意义。</p>
<h3>Base 64编码</h3>
<p><a href="http://en.wikipedia.org/wiki/Base64" target="_blank">Base 64</a>编码是一个编码规则，通过它数据被转化成二进制码，然后组合成一个base 64码的序列。Base 64码包括大写和小写的字母A到Z，数字，符号+和/。=号是用来填充用的（可以查看Wikipedia上的文章获取更多的信息）。你真正需要知道的是比起其他的编码，base 64编码会使编码过的数据变得更小。</p>
<p>下面的例子是一张GIF图片用base 64进行编码后的data URI（<a href="http://www.websiteoptimization.com/speed/tweak/inline-images/" target="_blank">来源</a>）：</p>
<pre class="brush:text;gutter:false;">
data:image/gif;base64,R0lGODlhEAAOALMAAOazToeHh0tLS/7LZv/0jvb29t/f3//Ub//ge
8WSLf/rhf/3kdbW1mxsbP//mf///yH5BAAAAAAALAAAAAAQAA4AAARe8L1Ekyky67QZ1h
LnjM5UUde0ECwLJoExKcppV0aCcGCmTIHEIUEqjgaORCMxIC6e0CcguWw6aFjsVMkkIr7g
77ZKPJjPZqIyd7sJAgVGoEGv2xsBxqNgYPj/gAwXEQA7
</pre>
<p>同一张图片如果不用base 64编码的话将会如下显示：</p>
<pre class="brush:text;gutter:false;">
data:image/gif,GIF89a%22%00%1B%00%F7%00%00lll%D6%D6%D6%FF%EB%85
%FF%E0%7B%FF%F7%91%FF%D4o%DF%DF%DF%F6%F6%F6%87%87%87%FE
%CBf%FF%F4%8E%E6%B3NKKK%C5%92-%FF%FF%99%FF%FF%FF%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00
%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%2C%00%00
%00%00%22%00%1B%00%00%08%A9%00%1F%08%1CH%B0%A0%C1%83%08
%13*%5C%C8%B0%A1%C3%87%10%23J%9CH%91%60%83%8B%0D%0C%1C
%A8h%B0%81%C5%00%1B9%0A%F4%E8%A0%A4%83%07%181j%9C%D8%80
%80%82%97%2F%0B6%40%60%80%A5%00%01)s%AA%94%D8%60%80G%84
%02P%22%E0Y%A0%81%C9%A3%25%138h%00%80g%02%A3%04%A2J%8D
%BA%60i%D3%88%0D%9E%3A%B8%C9%95kU%A6N%8D%0E%18Kv%EC%D7
%AB%10%B3%1A-%C0%B6-%5B%A3%60%23%1A%D0I%97%C1%D0%88%07
%02%20%00%C0%B7%AF_%00%08%02L%3C%60%20%80%E1%C3%88%03
%AC%14%C9%B8%B1%E3%C7%90%23K%9EL0%20%00%3B
</pre>
<p>就大小来说，用base 64编码的图片完胜，它明显小多了。</p>
<p>注意：Base 64编码事实上会使图片的大小变大。然而，如果你使用了HTTP压缩，那么你并不会察觉到有什么差异，因为base 64编码的数据的压缩性极好。如果因为某些原因不能使用HTTP压缩的话，那么你可能会想知道你发送的数据究竟有多大，然后权衡下是否值得这么做。</p>
<h3>不仅仅用于图像</h3>
<p>尽管大部分人在谈论data URI作为在HTML或者CSS文件里嵌入图片的方法，但这里并没有指定是图片。你可以编码然后嵌入任何类型的文件，甚至是HTML本身。Ian Hickson，HTML 5名人（或者恶人，视乎你怎么看）提供了一个<a href="http://software.hixie.ch/utilities/cgi/data/data" target="_blank">工具</a>让你体验下data URI。默认的例子是使用或者不用base 64编码把一个HTML文件转变成data URI。体验一下这个data URI产生器可以帮助你具体化一下核心的概念。</p>
<p>注意：IE8对data URI有<a href="http://msdn.microsoft.com/en-us/library/cc848897(VS.85).aspx" target="_blank">安全限制</a>，使得data URI对于非图片的数据的用处大打折扣。</p>
<h3>性能影响</h3>
<p>data URI最有趣的地方是它可以让你把文件嵌入到其他文件中。大多数的<a href="http://www.websiteoptimization.com/speed/tweak/inline-images/" target="_blank">文章</a>都把焦点放在把data URI嵌入到CSS文件里改善性能上。实际上，大量的<a href="http://stevesouders.com/hpws/rule-min-http.php" target="_blank">研究</a>表明，HTTP请求是影响网页性能最主要的因素之一，减少请求的数量可以改善页面的性能。实际上，“最小化HTTP请求”是<a href="http://developer.yahoo.com/performance/rules.html" target="_blank">Yahoo! Exceptional Performance Best Practices</a>的第一准则，它特别提到了data URI：</p>
<blockquote><p>内联图像使用了data URI把图像数据嵌入到页面中，会增加HTML文档的大小。把内联图像在（已缓存的）样式表里组合起来可以减少HTTP请求和避免页面大小的增加。内联图像还没有得到所有主流浏览器的支持。</p></blockquote>
<p>这对使用data URI来说是个很好的建议：把它们用在缓存频率最高的地方。通过HTTP下载的普通图片会根据它们的header和浏览器设置进行缓存，这样它们就不用每次请求都被重新下载。Data URI会被当作装载它的那个文件的一部分，所以它是所嵌入的HTML或者CSS文件的一部分。这意味着data URI没有单独的缓存控制策略。嵌入data URI会使你的文件变大，如果文件经常改动的话（例如博客的首页），那么这个变大的文件就会被频繁的下载，使网页速度变慢。</p>
<p>最简单的使用方法是把data URI嵌入到一个会被经常性缓存的外部样式表里。这样的话，在浏览器缓存为空的情况下，网站速度会比较快（因为少了额外的请求），而在浏览器存在缓存的情况下，则体验是一样的。</p>
<h3>浏览器支持情况</h3>
<p>绝大多数的现代浏览器都支持data URI：<br />
Firefox 2+<br />
Opera 7.2+ - data URI必须少于4100个字符<br />
Chrome (all versions)<br />
Safari (all versions)<br />
Internet Explorer 8+ - data URI必须小于32k</p>
<p>由于版本低于8的IE浏览器不支持data URI，你需要决定是否值得为这些不支持data URI的浏览器提供替代的东西（可以看看<a href="http://www.phpied.com/mhtml-when-you-need-data-uris-in-ie7-and-under/" target="_blank">Stoyan的文章</a>）。</p>
<h3>结论</h3>
<p>Data URI对网页来说是个很有趣和独特的概念，可能在将来会被越来越广泛的应用，暂时来说，它大概是最适合用于那些跟性能相关的任务上，但是谁也不知道将会会怎样。但目前你能看到的是使用data URI获取图片时减少额外的HTTP请求带来的一些性能上的优化。另外，Data URI还带来了使用JS动态产生图片的可能性，尽管浏览器对&lt;canvas&gt;的支持的不断增加可能会使得这个方法被淘汰。</p>
<p>Translated by <a href="http://www.icyfire.me/">icyfire</a> @ Aug 05, 2010 updated @ Oct 22, 2011<br />
源文：<a href="http://www.nczonline.net/blog/2009/10/27/data-uris-explained/" target="_blank">Data URIs explained</a><br />
作者：<a href="http://www.nczonline.net/" target="_blank">Nicholas C. Zakas</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.icyfire.me/2010/08/data-uris-explained/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[翻译]jQuery的show/hide性能测试</title>
		<link>http://www.icyfire.me/2010/07/jquery-showhide-performance/</link>
		<comments>http://www.icyfire.me/2010/07/jquery-showhide-performance/#comments</comments>
		<pubDate>Mon, 26 Jul 2010 10:38:02 +0000</pubDate>
		<dc:creator>icyfire</dc:creator>
				<category><![CDATA[网站前端]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://www.icyfire.me/?p=927</guid>
		<description><![CDATA[这篇文章是jQuery各种show/hide方式的性能测试。作者之所以测试这个源于Robert Duffy在San Francisco举行的jQuery大会上的一句话：“.hide()和.show()的执行速度会比直接改变css慢”。但由于未能找Robert Duffy问明原因，所以作者就自己去做了这个测试。下面的翻译并不是全文翻译，只节选了一些重点。

用作测试的是一个含有100个div的HTML页面，div带有class和一些内容。为了排除掉寻找这些div所花费的时间，所以把选择器$('div')缓存起来了。用作测试的jQuery版本是1.4.2，所以测试结果也只是针对这个版本，在其他版本可能就不是这些结果了。

测试的jQuery方法分别是：
<ul>
<li>.toggle()</li>
<li>.show() 和 .hide()</li>
<li>.css({'display':'none'}) 和 .css({'display':'block'})</li>
<li>.addClass('hide') 和 .removeClass('hide')</li>
<li>改变&#60;style&#62;元素的一个属性</li>
</ul> <a href="http://www.icyfire.me/2010/07/jquery-showhide-performance/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div style="font-size:12px;">
这篇文章是jQuery各种show/hide方式的性能测试。作者之所以测试这个源于Robert Duffy在San Francisco举行的jQuery大会上的一句话：“.hide()和.show()的执行速度会比直接改变css慢”。但由于未能找Robert Duffy问明原因，所以作者就自己去做了这个测试。下面的翻译并不是全文翻译，只节选了一些重点。</p>
<p>用作测试的是一个含有100个div的HTML页面，div带有class和一些内容。为了排除掉寻找这些div所花费的时间，所以把选择器$('div')缓存起来了。用作测试的jQuery版本是1.4.2，所以测试结果也只是针对这个版本，在其他版本可能就不是这些结果了。</p>
<p>测试的jQuery方法分别是：</p>
<ul>
<li>.toggle()</li>
<li>.show() 和 .hide()</li>
<li>.css({'display':'none'}) 和 .css({'display':'block'})</li>
<li>.addClass('hide') 和 .removeClass('hide')</li>
<li>改变&lt;style&gt;元素的一个属性</li>
</ul>
<h2>.show() 和 .hide()</h2>
<p><strong>在所有浏览器中，这两个方法在隐藏DOM元素上相对来说比较慢。</strong>主要原因在于.hide()方法必须先保存元素的"display"属性，这样.show()才能把元素恢复到原来的状态。这里用到了.data()这个jQuery方法，把信息保存在DOM元素上。为了达到这个目的，.hide()在每个元素上循环了两次，一次用来保存当前的"display"值，一次用来更新样式"display"为"none"。根据源代码上的注释，这样做是为了防止浏览器在每个循环上进行重新渲染（reflow）。.hide()方法还会检查你是否传递了使用动画效果的参数，就算传入一个"0"也会让性能大打折扣。在第一次调用.hide()的时候性能最慢，在之后再调用则会变快。</p>
<table class="mytable" cellspacing="0" style="width:100%;margin-bottom:10px;">
<tr>
<th scope="row" class="left top">Browser</th>
<th scope="col">hide/show</th>
</tr>
<tr>
<td class="spec">FireFox 3.6</td>
<td>29ms / 10ms</td>
</tr>
<tr>
<td class="spec">Safari 4.05</td>
<td>6ms / 1ms</td>
</tr>
<tr>
<td class="spec">Opera 10.10</td>
<td>9ms / 1ms</td>
</tr>
<tr>
<td class="spec">Chrome 5.0.3</td>
<td>5ms / 1ms</td>
</tr>
<tr>
<td class="spec">IE 6.0</td>
<td>31ms / 16ms</td>
</tr>
<tr>
<td class="spec">IE 7.0</td>
<td>15ms / 16ms</td>
</tr>
</table>
<h2>.toggle()</h2>
<p><strong>这个方法是最慢的。</strong>它会检查选择器返回的每一个元素当前是否可见，如果可见的话就调用.hide()方法，不可见则调用.show()方法。不但如此，它不仅会检查你是否传递了一个boolean值进去阻止.hide()或者.show()的执行，还会检查看你是否传入了function来进行切换（toggle）而不是对可见性进行切换。看起来这个方法还有很大的改善空间，例如可以先一次过把隐藏的元素select出来，然后调用.show()方法，同时把其余的元素select出来调用.hide()方法。</p>
<table class="mytable" cellspacing="0" style="width:100%;margin-bottom:10px;">
<tr>
<th scope="row" class="left top">Browser</th>
<th scope="col">hide/show</th>
</tr>
<tr>
<td class="spec">FireFox 3.6</td>
<td>80ms / 59ms</td>
</tr>
<tr>
<td class="spec">Safari 4.05</td>
<td>24ms / 30ms</td>
</tr>
<tr>
<td class="spec">Opera 10.10</td>
<td>67ms / 201ms</td>
</tr>
<tr>
<td class="spec">Chrome 5.0.3</td>
<td>55ms / 20ms</td>
</tr>
<tr>
<td class="spec">IE 6.0</td>
<td>296ms / 78ms</td>
</tr>
<tr>
<td class="spec">IE 7.0</td>
<td>328ms / 47ms</td>
</tr>
</table>
<h2>.addClass() 和 .removeClass()</h2>
<p>这是两个很漂亮的隐藏/显示DOM元素方法。<b>在Firefox上它的速度是.show()和.hide()的两倍，而在Safari上则是三倍。不过在IE6，IE7，Chrome和Opera上，两种方法几乎没什么差别。</b>值得一提的是，对于100个DOM节点来说，两种方法在Firefox上相差18ms，在Safari相差4ms，速度的差异只会体现在大量节点选择的时候。不过增加和移除class需要你花费更多的工作，因为你需要创建一个用于隐藏的class，然后还要时刻关注着这个class的优先级以保证DOM能隐藏。jQuery增加和移除class是通过字符串操作的，所以我觉得随着元素上class数量的增加，这个方法会变慢，但是我还没对此进行测试过。</p>
<table class="mytable" cellspacing="0" style="width:100%;margin-bottom:10px;">
<tr>
<th scope="row" class="left top">Browser</th>
<th scope="col">hide/show</th>
</tr>
<tr>
<td class="spec">FireFox 3.6</td>
<td>11ms / 11ms</td>
</tr>
<tr>
<td class="spec">Safari 4.05</td>
<td>2ms / 2ms</td>
</tr>
<tr>
<td class="spec">Opera 10.10</td>
<td>6ms / 3ms</td>
</tr>
<tr>
<td class="spec">Chrome 5.0.3</td>
<td>3ms / 1ms</td>
</tr>
<tr>
<td class="spec">IE 6.0</td>
<td>47ms / 32ms</td>
</tr>
<tr>
<td class="spec">IE 7.0</td>
<td>15ms / 16ms</td>
</tr>
</table>
<h2>.css({'display':'none'}) 和 .css({'display':'block'})</h2>
<p>这两个方法也很漂亮。<b>相对于.addClass()和.removeClass()，IE6/7和Opera上的速度都得到了提升，而在其他浏览器上则能保持水准。</b>当你知道要改变的元素的当前display样式，或者没有通过inline的方式去改变元素的display样式时，这两个方法很好用。如果你通过inline的方式改变了display样式，那么你需要确保在使得元素重新可见时display值要设置正确。如果你只是使用了元素的默认display值或者在css里设置display值，那么你只需要用类似.css({'display':''})的方法移除样式，元素就会恢复到它在css上的样式或者默认display值。作为一个类库，jQuery不能假定元素的display不是通过inline方式设置的，所以它需要被人手的去确定。不过既然你知道你不会去inline的设置display，那么你就可以去避免这个造成缓慢的主要因素。</p>
<table class="mytable" cellspacing="0" style="width:100%;margin-bottom:10px;">
<tr>
<th scope="row" class="left top">Browser</th>
<th scope="col">hide/show</th>
</tr>
<tr>
<td class="spec">FireFox 3.6</td>
<td>14ms / 12ms</td>
</tr>
<tr>
<td class="spec">Safari 4.05</td>
<td>2ms / 1ms</td>
</tr>
<tr>
<td class="spec">Opera 10.10</td>
<td>2ms / 2ms</td>
</tr>
<tr>
<td class="spec">Chrome 5.0.3</td>
<td>2ms / 1ms</td>
</tr>
<tr>
<td class="spec">IE 6.0</td>
<td>16ms / 16ms</td>
</tr>
<tr>
<td class="spec">IE 7.0</td>
<td>0ms / 0ms  // 少于15ms会变成0ms，具体看<a href="http://ejohn.org/blog/accuracy-of-javascript-time/">这里<br />
</a></td>
</tr>
</table>
<h2>禁止样式表</h2>
<p>纯粹为了好玩，我想：如果我们不在每个dom节点上花功夫，而是去捣鼓样式表会怎样呢？这样会提高速度吗？其实就日常使用来说，上面的测试用到的方法已经足够快了，但是如果页面上有10000个节点需要进行隐藏和显示呢？只是把它们全部选择出来就已经够慢了。如果我可以控制样式表，那么就可以完全避免这些时间花费了。不过我得告诉你，这个方法是有很大风险的。</p>
<p>风险在于控制样式表时的跨浏览器问题。首先，我尝试能不能通过jQuery插入一个带有class的"style"标签，但是却出现了跨浏览器问题。然后我尝试用javascript去创建stylesheet节点和class，但是实在有太多的API了，要搞清楚需要花不少的时间。最后，放弃了编程的方式，我在head区里写了一个带有class的style标签。通过编程的方式来创建stylesheet实在是太慢了，但是如果它一旦被创建好，那么给它一个ID和使用它的"disabled"属性就是轻而易举的事情了。</p>
<pre class="brush: html; gutter: true">
<style id="special_hide">.special_hide { display: none; }</style>

<!--  ...  -->
<div class="special_hide">Special hide DIV</div>
</pre>
<p>然后在javascript里：</p>
<pre class="brush: javascript; gutter: true">
$('#special_hide').attr('disabled', 'true');
</pre>
<p>搞定！所有带有"special_hide"这个class的元素都显示出来了。要隐藏它们，你只需要……</p>
<pre class="brush: css; gutter: true">
$('#special_hide').attr('disabled', 'false');
</pre>
<p>现在它们全部都隐藏了。<strong>总的javascript耗时在所有浏览器上都是0-1ms。</strong>你的javascript只是用来改变一个属性。当然，浏览器还是需要花费时间去重新渲染页面的，但是实际上你已经避免了javascript的处理时间。如果你调用了.toggle()，.hide()或者 .css()这几个方法，那么这个方法就会失效。因为那几个方法会通过内联方式设置css样式，这些样式有更高的优先级。要重新使这个方法生效，只需调用.css('display', '') 把内联的样式移除掉。这个方法同样需要花费你更多的精力，因为那需要去定义class，同时把这些class赋给页面上需要进行显示/隐藏的元素，但是如果你所要处理的元素数量是极其庞大的话，那么这也许是值得的。</p>
<p>简要回顾一下，下面是改变元素显示状态的方法，按照最快到最慢的次序排列：</p>
<ul>
<li style="list-style-type:decimal;">禁用/启用样式表</li>
<li style="list-style-type:decimal;">.css('display', ''), .css('display', 'none')</li>
<li style="list-style-type:decimal;">.addClass(), .removeClass()</li>
<li style="list-style-type:decimal;">.show(), .hide()</li>
<li style="list-style-type:decimal;">.toggle()</li>
</ul>
<p>需要注意的是，在大多数的情况下，这些方法都足够的快了。当你要操作很大的jQuery集合时，那么.show() 和 .hide()方法在IE下就会变得很慢了，这是你可能要用addClass() 或者 .removeClass()方法。 禁用/启用样式表的方法只有在很极端的情况下才有必要用到。</p>
<p>Updated @ 2011.08.30<br />
今天看回这篇文章，发现jQuery跟浏览器的版本都升了不少了，于是产生了重新测试的念头。jQuery使用目前最新的1.6.2版本。</p>
<h2>.show() 和 .hide()</h2>
<table class="mytable" cellspacing="0" style="width:100%;margin-bottom:10px;">
<tr>
<th scope="row" class="left top">Browser</th>
<th scope="col">hide/show</th>
</tr>
<tr>
<td class="spec">FireFox 6.0</td>
<td>10ms / 3ms</td>
</tr>
<tr>
<td class="spec">Safari 5.1</td>
<td>8ms / 6ms</td>
</tr>
<tr>
<td class="spec">Opera 11.50</td>
<td>19ms / 19ms</td>
</tr>
<tr>
<td class="spec">Chrome 13.0.7</td>
<td>7ms / 7ms</td>
</tr>
<tr>
<td class="spec">IE 8.0</td>
<td>7ms / 5ms</td>
</tr>
<tr>
<td class="spec">IE 9.0</td>
<td>2ms / 12ms</td>
</tr>
</table>
<h2>.toggle()</h2>
<table class="mytable" cellspacing="0" style="width:100%;margin-bottom:10px;">
<tr>
<th scope="row" class="left top">Browser</th>
<th scope="col">hide/show</th>
</tr>
<tr>
<td class="spec">FireFox 6.0</td>
<td>55ms / 64ms</td>
</tr>
<tr>
<td class="spec">Safari 5.1</td>
<td>25ms / 27ms</td>
</tr>
<tr>
<td class="spec">Opera 11.50</td>
<td>48ms / 40ms</td>
</tr>
<tr>
<td class="spec">Chrome 13.0.7</td>
<td>22ms / 25ms</td>
</tr>
<tr>
<td class="spec">IE 8.0</td>
<td>55ms / 71ms</td>
</tr>
<tr>
<td class="spec">IE 9.0</td>
<td>32ms / 35ms</td>
</tr>
</table>
<h2>.addClass() 和 .removeClass()</h2>
<table class="mytable" cellspacing="0" style="width:100%;margin-bottom:10px;">
<tr>
<th scope="row" class="left top">Browser</th>
<th scope="col">hide/show</th>
</tr>
<tr>
<td class="spec">FireFox 6.0</td>
<td>7ms / 7ms</td>
</tr>
<tr>
<td class="spec">Safari 5.1</td>
<td>1ms / 1ms</td>
</tr>
<tr>
<td class="spec">Opera 11.50</td>
<td>1ms / 1ms</td>
</tr>
<tr>
<td class="spec">Chrome 13.0.7</td>
<td>1ms / 1ms</td>
</tr>
<tr>
<td class="spec">IE 8.0</td>
<td>2ms / 2ms</td>
</tr>
<tr>
<td class="spec">IE 9.0</td>
<td>1ms / 1ms</td>
</tr>
</table>
<h2>.css({'display':'none'}) 和 .css({'display':'block'})</h2>
<table class="mytable" cellspacing="0" style="width:100%;margin-bottom:10px;">
<tr>
<th scope="row" class="left top">Browser</th>
<th scope="col">hide/show</th>
</tr>
<tr>
<td class="spec">FireFox 6.0</td>
<td>8ms / 8ms</td>
</tr>
<tr>
<td class="spec">Safari 5.1</td>
<td>1ms / 1ms</td>
</tr>
<tr>
<td class="spec">Opera 11.50</td>
<td>1ms / 1ms</td>
</tr>
<tr>
<td class="spec">Chrome 13.0.7</td>
<td>1ms / 1ms</td>
</tr>
<tr>
<td class="spec">IE 8.0</td>
<td>2ms / 2ms</td>
</tr>
<tr>
<td class="spec">IE 9.0</td>
<td>1ms / 1ms</td>
</tr>
</table>
<h2>禁止样式表</h2>
<table class="mytable" cellspacing="0" style="width:100%;margin-bottom:10px;">
<tr>
<th scope="row" class="left top">Browser</th>
<th scope="col">hide/show</th>
</tr>
<tr>
<td class="spec">FireFox 6.0</td>
<td>1ms / 1ms</td>
</tr>
<tr>
<td class="spec">Safari 5.1</td>
<td>1ms / 1ms</td>
</tr>
<tr>
<td class="spec">Opera 11.50</td>
<td>1ms / 1ms</td>
</tr>
<tr>
<td class="spec">Chrome 13.0.7</td>
<td>1ms / 1ms</td>
</tr>
<tr>
<td class="spec">IE 8.0</td>
<td>1ms / 1ms</td>
</tr>
<tr>
<td class="spec">IE 9.0</td>
<td>1ms / 1ms</td>
</tr>
</table>
<p>.toggle()方法依然是最慢的，禁用样式表的方法依然是最快的。.addClass()跟.css()旗鼓相当，当然如何把测试的div再增加点，应该还是能分高下的。另外让我比较意外的是Firefox在这两个方法里的表现实在弱爆了……</p>
</div>
<p>Translated by <a href="http://www.icyfire.me/">icyfire</a> @ company Jul 26, 2010<br />
Updated 2011.08.30<br />
源文：<a href="http://www.learningjquery.com/2010/05/now-you-see-me-showhide-performance">Now you see me… show/hide performance</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.icyfire.me/2010/07/jquery-showhide-performance/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Chrome 和 Opera 都比土豆还要快</title>
		<link>http://www.icyfire.me/2010/05/chrome-%e5%92%8c-opera-%e9%83%bd%e6%af%94%e5%9c%9f%e8%b1%86%e8%bf%98%e8%a6%81%e5%bf%ab/</link>
		<comments>http://www.icyfire.me/2010/05/chrome-%e5%92%8c-opera-%e9%83%bd%e6%af%94%e5%9c%9f%e8%b1%86%e8%bf%98%e8%a6%81%e5%bf%ab/#comments</comments>
		<pubDate>Sat, 29 May 2010 13:28:13 +0000</pubDate>
		<dc:creator>icyfire</dc:creator>
				<category><![CDATA[网站前端]]></category>
		<category><![CDATA[Chrome]]></category>
		<category><![CDATA[Opera]]></category>
		<category><![CDATA[视频]]></category>

		<guid isPermaLink="false">http://www.icyfire.me/?p=929</guid>
		<description><![CDATA[5月初，爱好吹嘘 Chrome 速度的 Google 又制作了一个创意巧妙的视频，其中的一个片段是 Chrome 打开页面速度 PK 飞行的土豆速度。Opera 的人看了这个视频后也灵感大发，同样拿 Opera 和土豆拼起了速度，不过他们比的是，煮土豆的速度…… <a href="http://www.icyfire.me/2010/05/chrome-%e5%92%8c-opera-%e9%83%bd%e6%af%94%e5%9c%9f%e8%b1%86%e8%bf%98%e8%a6%81%e5%bf%ab/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>5月初，爱好吹嘘 Chrome 速度的 Google 又制作了一个创意巧妙的视频，其中的一个片段是 Chrome 打开页面速度 PK 飞行的土豆速度。Opera 的人看了这个视频后也灵感大发，同样拿 Opera 和土豆拼起了速度，不过他们比的是，煮土豆的速度……</p>
<p><embed src="http://player.youku.com/player.php/sid/XMTc2ODU2OTI0/v.swf" quality="high" width="480" height="400" align="middle" allowScriptAccess="sameDomain" type="application/x-shockwave-flash"></embed></p>
<p>这是Google的。</p>
<p><embed src="http://player.youku.com/player.php/sid/XMTc2ODQzODA0/v.swf" quality="high" width="480" height="400" align="middle" allowScriptAccess="sameDomain" type="application/x-shockwave-flash"></embed></p>
<p>上面是Opera的恶搞版，真的太搞了……</p>
]]></content:encoded>
			<wfw:commentRss>http://www.icyfire.me/2010/05/chrome-%e5%92%8c-opera-%e9%83%bd%e6%af%94%e5%9c%9f%e8%b1%86%e8%bf%98%e8%a6%81%e5%bf%ab/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

