<?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>Zihua Li</title>
	<atom:link href="http://zihua.li/feed/" rel="self" type="application/rss+xml" />
	<link>http://zihua.li</link>
	<description>Web Developer &#38; Internet Specialist</description>
	<lastBuildDate>Sun, 20 May 2012 09:21:24 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>短链系统的实现：高进制转换</title>
		<link>http://zihua.li/2012/05/implement-shortlink-using-base-62/</link>
		<comments>http://zihua.li/2012/05/implement-shortlink-using-base-62/#comments</comments>
		<pubDate>Sun, 20 May 2012 09:21:24 +0000</pubDate>
		<dc:creator>Luin</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[短链]]></category>
		<category><![CDATA[进制转换]]></category>

		<guid isPermaLink="false">http://zihua.li/?p=235</guid>
		<description><![CDATA[每个短链系统都需要一个能生成不重复的短链的算法。最简单的方法就是以数字为短链，如： http://domain/1http://domain/2 &#8230; 但是一百万个短链后短链的位数就猛增到了7位，像twitter等网站的短链服务显然没有办法接受这样的位数增长速度。为了充分减少短链位数，我们希望短链拥有更大的字符空间。 一个不错的方法是将数字转换成更高进制的数，比如62进制（即包含字符&#8217;0&#8242;..&#8217;1&#8242;, &#8216;a&#8217;..&#8217;z', &#8216;A&#8217;..&#8217;Z'）。 JavaScript代码如下： [crayon-4fb8dafb84d2f/] 如果传入的value是数字，就会将value转成字符空间为space，进制为space.length的数字（字符串）；如果传入的value是字符串，则同理会将value转换成10进制数字。如： > generateShortLink(&#8217;0123456789abcdef&#8217;, 255) &#8216;ff&#8217; > generateShortLink(&#8217;01&#8242;, 255) &#8217;11111111&#8242; > generateShortLink(&#8217;0123456789abcdefghijklmnopqrstuvwxyz&#8217;, 123456789) &#8217;21i3v9&#8242; 生成短链时先通过自增方式获得一个十进制数字代表短链id，然后将该id通过generateShortLink()转换成62进制(或者去除1和l，o和0等易混淆字符，根据使用场景是用户手动输入还是直接点击链接来做更多优化)短链显示给用户。用户访问短链时再把短链转换成10进制id，然后查询数据库将实际地址返还给用户。]]></description>
			<content:encoded><![CDATA[<p>每个短链系统都需要一个能生成不重复的短链的算法。最简单的方法就是以数字为短链，如：<br />
http://domain/1<br />http://domain/2<br />
&#8230;<br />
但是一百万个短链后短链的位数就猛增到了7位，像twitter等网站的短链服务显然没有办法接受这样的位数增长速度。为了充分减少短链位数，我们希望短链拥有更大的字符空间。</p>
<p>一个不错的方法是将数字转换成更高进制的数，比如62进制（即包含字符&#8217;0&#8242;..&#8217;1&#8242;, &#8216;a&#8217;..&#8217;z', &#8216;A&#8217;..&#8217;Z'）。<br />
JavaScript代码如下：</p><pre class="crayon-plain-tag">generateShortLink = function(space, value) {
  if (typeof value === 'number') {
    var result = '';
    do {
      result = space[value % space.length] + result;
      value = Math.floor(value / space.length);
    } while (value &amp;gt; 0)
  } else if (typeof value === 'string') {
    var result = 0;
    for (var i = 0; i &amp;lt; value.length; ++i) {
      result += space.indexOf(value[i]) * Math.pow(space.length, value.length - i - 1);
    }
  }
  return result;
};</pre><p> </p>
<p>如果传入的value是数字，就会将value转成字符空间为space，进制为space.length的数字（字符串）；如果传入的value是字符串，则同理会将value转换成10进制数字。如：</p>
<blockquote><p>
> generateShortLink(&#8217;0123456789abcdef&#8217;, 255)<br />
&#8216;ff&#8217;<br />
> generateShortLink(&#8217;01&#8242;, 255)<br />
&#8217;11111111&#8242;<br />
> generateShortLink(&#8217;0123456789abcdefghijklmnopqrstuvwxyz&#8217;, 123456789)<br />
&#8217;21i3v9&#8242;
</p></blockquote>
<p>生成短链时先通过自增方式获得一个十进制数字代表短链id，然后将该id通过generateShortLink()转换成62进制(或者去除1和l，o和0等易混淆字符，根据使用场景是用户手动输入还是直接点击链接来做更多优化)短链显示给用户。用户访问短链时再把短链转换成10进制id，然后查询数据库将实际地址返还给用户。</p>
]]></content:encoded>
			<wfw:commentRss>http://zihua.li/2012/05/implement-shortlink-using-base-62/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MySQL迁移到Redis记(重写记)</title>
		<link>http://zihua.li/2012/05/mysql-to-redis/</link>
		<comments>http://zihua.li/2012/05/mysql-to-redis/#comments</comments>
		<pubDate>Sat, 19 May 2012 17:38:39 +0000</pubDate>
		<dc:creator>Luin</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Cache]]></category>
		<category><![CDATA[CoffeeScript]]></category>
		<category><![CDATA[MongoDB]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[node.js]]></category>
		<category><![CDATA[Redis]]></category>

		<guid isPermaLink="false">http://zihua.li/?p=225</guid>
		<description><![CDATA[前些日子，一个悠闲又不悠闲的下午，我还在用Node.js写着某个移动互联网应用的API服务端。那时还是用MySQL作为数据库，一切都很好，所有功能正常运行。可是有很多问题让人不安： 1. 频繁的产品功能变化让MySQL跟不上 产品初期功能变化很频繁，其中很多变化都不得不对数据库结构做出更改。对于MySQL来说，也许是改一个字段名方便SELECT，也许是把一个字段移到另一个表方便索引，也许是要对多个表重新设计来达到修改要求（这种情况最惨烈，但开发过程中遇到过不止一次）。 2. 符合范式的设计让JOIN在SELECT语句中大行其道 尽管在设计时已经做好规划，保证在多数查询时不会用到JOIN，但是在其它不少地方仍然很难回避两表甚至多表联查，一些模块中SQL语句的复杂度甚至能达到大学数据库原理考试时考查的SQL语句题目的水平。写起来烦，想想实际运行情况，也不禁为MySQL同学捏一把汗。于是后来对复杂的MySQL语句增加了Cache，Redis第一次在这个项目登场就是干这个的，当时Cache的设计思路是： Redis存储两份数据，一份是数据缓存，一份是数据的最新版本号，执行复杂SQL查询时先检查这个查询在Redis里有没有数据缓存且对比数据的最新的版本号看当前数据缓存是不是最新的，是的话就读出来直接返回，不是的话查询MySQL得出结果并保存在Redis数据缓存中。如果更新了会影响这个查询结果的数据的话则简单地将Redis里该数据的最新版本号加1即可。 这个设计很简单实用，但很快问题就暴露出来了：因为缓存的加入导致整个系统更复杂，而且随着MySQL数据库结构的不断复杂，单纯加入缓存无法根本上解决这一问题。更重要的是，由于读写频率基本保持在1:1，导致缓存命中率极低，不如不用。 一切问题的解决方案都是NoSQL 上述问题让我重新考虑是否用NoSQL替换MySQL。关于NoSQL数据库我接触过的为MongoDB和Redis，最后选择Redis的原因是因为系统中已经使用了Redis做Cache，对Redis了解更多。 现在的API服务端代码已经从Node.js(JavaScript) + C + MySQL迁移到Node.js(CoffeeScript) + C + Redis。通过实践，使用Redis后的代码更易维护，更加整洁，性能也更高。同时在迁移时写了一个简单的Redis ORM模块，用起来十分方便。]]></description>
			<content:encoded><![CDATA[<p>前些日子，一个悠闲又不悠闲的下午，我还在用Node.js写着某个移动互联网应用的API服务端。那时还是用MySQL作为数据库，一切都很好，所有功能正常运行。可是有很多问题让人不安：</p>
<p><strong>1. 频繁的产品功能变化让MySQL跟不上</strong><br />
产品初期功能变化很频繁，其中很多变化都不得不对数据库结构做出更改。对于MySQL来说，也许是改一个字段名方便SELECT，也许是把一个字段移到另一个表方便索引，也许是要对多个表重新设计来达到修改要求（这种情况最惨烈，但开发过程中遇到过不止一次）。</p>
<p><strong>2. 符合范式的设计让JOIN在SELECT语句中大行其道</strong><br />
尽管在设计时已经做好规划，保证在多数查询时不会用到JOIN，但是在其它不少地方仍然很难回避两表甚至多表联查，一些模块中SQL语句的复杂度甚至能达到大学数据库原理考试时考查的SQL语句题目的水平。写起来烦，想想实际运行情况，也不禁为MySQL同学捏一把汗。于是后来对复杂的MySQL语句增加了Cache，Redis第一次在这个项目登场就是干这个的，当时Cache的设计思路是：<br />
Redis存储两份数据，一份是数据缓存，一份是数据的最新版本号，执行复杂SQL查询时先检查这个查询在Redis里有没有数据缓存且对比数据的最新的版本号看当前数据缓存是不是最新的，是的话就读出来直接返回，不是的话查询MySQL得出结果并保存在Redis数据缓存中。如果更新了会影响这个查询结果的数据的话则简单地将Redis里该数据的最新版本号加1即可。<br />
这个设计很简单实用，但很快问题就暴露出来了：因为缓存的加入导致整个系统更复杂，而且随着MySQL数据库结构的不断复杂，单纯加入缓存无法根本上解决这一问题。更重要的是，由于读写频率基本保持在1:1，导致缓存命中率极低，不如不用。</p>
<p><strong>一切问题的解决方案都是NoSQL</strong><br />
上述问题让我重新考虑是否用NoSQL替换MySQL。关于NoSQL数据库我接触过的为MongoDB和Redis，最后选择Redis的原因是因为系统中已经使用了Redis做Cache，对Redis了解更多。</p>
<p>现在的API服务端代码已经从Node.js(JavaScript) + C + MySQL迁移到Node.js(CoffeeScript) + C + Redis。通过实践，使用Redis后的代码更易维护，更加整洁，性能也更高。同时在迁移时写了一个简单的Redis ORM模块，用起来十分方便。</p>
]]></content:encoded>
			<wfw:commentRss>http://zihua.li/2012/05/mysql-to-redis/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>纪念人生中收到的第一枚假币</title>
		<link>http://zihua.li/2012/05/first-bogus-banknote-i-received/</link>
		<comments>http://zihua.li/2012/05/first-bogus-banknote-i-received/#comments</comments>
		<pubDate>Mon, 14 May 2012 08:23:53 +0000</pubDate>
		<dc:creator>Luin</dc:creator>
				<category><![CDATA[Life]]></category>

		<guid isPermaLink="false">http://zihua.li/?p=221</guid>
		<description><![CDATA[今天中午叫了外卖，掏钱结账时送餐的小伙拿着我给的50元钱看了半天跟我说是假币，我半信半疑地拿过来仔细看了看，发现确实是假的，纸张的质感差距很大。再对着阳光看看水印，可把我笑喷了： 两只萌萌滴大眼睛有木有？ 想想来源，发现是某年某月某夜一个和蔼可亲的出租车司机师傅找给我的，估计人家也不知道是假币。 最后我把这张假币扔进了碎纸机，权当自己攒了把人品，遗憾的是张50元假币，恐怕也攒不了多少。]]></description>
			<content:encoded><![CDATA[<p>今天中午叫了外卖，掏钱结账时送餐的小伙拿着我给的50元钱看了半天跟我说是假币，我半信半疑地拿过来仔细看了看，发现确实是假的，纸张的质感差距很大。再对着阳光看看水印，可把我笑喷了：<br />
<a href="http://zihua.li/wp-content/uploads/2012/05/bogus_banknote.jpg"><img src="http://zihua.li/wp-content/uploads/2012/05/bogus_banknote.jpg" alt="" title="bogus_banknote" width="500" height="373" class="alignnone size-full wp-image-222" /></a><br />
两只萌萌滴大眼睛有木有？</p>
<p>想想来源，发现是某年某月某夜一个和蔼可亲的出租车司机师傅找给我的，估计人家也不知道是假币。</p>
<p>最后我把这张假币扔进了碎纸机，权当自己攒了把人品，遗憾的是张50元假币，恐怕也攒不了多少。</p>
]]></content:encoded>
			<wfw:commentRss>http://zihua.li/2012/05/first-bogus-banknote-i-received/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>我常用的Mac和iPhone软件</title>
		<link>http://zihua.li/2012/04/most-commonly-used-software-in-mac-iphone/</link>
		<comments>http://zihua.li/2012/04/most-commonly-used-software-in-mac-iphone/#comments</comments>
		<pubDate>Wed, 04 Apr 2012 16:30:40 +0000</pubDate>
		<dc:creator>Luin</dc:creator>
				<category><![CDATA[Life]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[mac]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://zihua.li/?p=215</guid>
		<description><![CDATA[最近买了Reeder的iOS版，感觉甚爽，尤其是和Read it later配合使用，给大家推荐一下；顺便列举一些我常用的Mac和iPhone软件。 Mac 浏览器 两年前的我还在整天和前端打交道，HTML, CSS, JavaScript写个不停，也就是在那个时候我买了自己的第一台MacBook，而开机的第一件事就是装浏览器，Safari, Opera, Chrome, Firefox, IETester(装在VMware的Windows XP里)全部都装上并摆在桌面上，看着心里就有底。 不过现在我仍然在用的浏览器只有Safari了，原因主要有： 写前端不再考虑IE6，而且有经验后写出来的网页直接放在IE7上也不会有什么问题，更不用说Firefox等现代浏览器（而且我现在很少写前端了）。 Command + Z可以撤销上一个关闭的标签（而不是Firefox的Command + Shift + T） Lion刚出时就支持全屏模式 我很喜欢它的外观啊（但我不喜欢它的图标） 前些日子出来个QQ浏览器，用起来同样很爽，也因此把Safari打入了几天冷宫。不过Bug频出让我不得不继续用我的Safari。 中文输入法 我在Mac用了好久的搜狗输入法，很好用，词库全，支持皮肤。但是偶尔也会出几个Bug，最典型的就是选词窗口关不掉，一直浮在上面恶心你，不过总体上还是很值得推荐的。 我现在用的是Lion自带的输入法，挺不错的，不再用搜狗输入法的原因除了上面提到的Bug以外，主要还是想“换换口味”。 下载 现在用QQ离线下载+Safari自带的下载，教育网连接QQ离线下载服务器速度还是很快的。迅雷什么的太卡太不稳定所以装上后用了几天就删掉了。 播放器 音乐播放器：无。我主要在网上听，经常用的是虾米。在线听歌的好处就是不用下载，随时更新。很适合我这样懒且不追求音质的人。 视频播放器：射手播放器，自动匹配字幕什么的太有爱的，真心离不开。 其它 Clean: 我实在是太喜欢这个小工具了。它能每天定时把桌面上的所有文件移动到Documents文件夹，对于我这个经常能把桌面塞满的人再适合不过了。 dRadio: 朋友做的豆瓣电台Mac客户端，UI和功能都无可挑剔，为了这个超赞的软件去用豆瓣电台吧！ Sequel Pro: 很棒的MySQL管理客户端，phpMyAdmin终于可以删掉了。补充一下，虽然名字里有&#8221;Pro&#8221;，不过人家确实是免费的哦。 iPhone iPhone下除了Reeder ＋ Read it later外简单列举一下我最近常用的软件和游戏： 随手记：记帐很好用，而且借助街旁API提供附近商家功能，借助我查查提供扫描条形码功能，很方便。 Draw Something：超火的游戏。 Game Dev Story：模拟经营游戏，经营一家你自己的游戏公司。虽然画面一般，但就游戏性而言简直就是神作。 Flick Soccer: [...]]]></description>
			<content:encoded><![CDATA[<p>最近买了Reeder的iOS版，感觉甚爽，尤其是和Read it later配合使用，给大家推荐一下；顺便列举一些我常用的Mac和iPhone软件。</p>
<h2>Mac</h2>
<p><strong>浏览器</strong><br />
两年前的我还在整天和前端打交道，HTML, CSS, JavaScript写个不停，也就是在那个时候我买了自己的第一台MacBook，而开机的第一件事就是装浏览器，Safari, Opera, Chrome, Firefox, IETester(装在VMware的Windows XP里)全部都装上并摆在桌面上，看着心里就有底。</p>
<p>不过现在我仍然在用的浏览器只有Safari了，原因主要有：</p>
<ul>
<li>写前端不再考虑IE6，而且有经验后写出来的网页直接放在IE7上也不会有什么问题，更不用说Firefox等现代浏览器（而且我现在很少写前端了）。
<li>Command + Z可以撤销上一个关闭的标签（而不是Firefox的Command + Shift + T）</li>
<li>Lion刚出时就支持全屏模式</li>
<li>我很喜欢它的外观啊（但我不喜欢它的图标）</li>
</ul>
<p>前些日子出来个QQ浏览器，用起来同样很爽，也因此把Safari打入了几天冷宫。不过Bug频出让我不得不继续用我的Safari。</p>
<p><strong>中文输入法</strong><br />
我在Mac用了好久的搜狗输入法，很好用，词库全，支持皮肤。但是偶尔也会出几个Bug，最典型的就是选词窗口关不掉，一直浮在上面恶心你，不过总体上还是很值得推荐的。</p>
<p>我现在用的是Lion自带的输入法，挺不错的，不再用搜狗输入法的原因除了上面提到的Bug以外，主要还是想“换换口味”。</p>
<p><strong>下载</strong><br />
现在用QQ离线下载+Safari自带的下载，教育网连接QQ离线下载服务器速度还是很快的。迅雷什么的太卡太不稳定所以装上后用了几天就删掉了。</p>
<p><strong>播放器</strong><br />
音乐播放器：无。我主要在网上听，经常用的是虾米。在线听歌的好处就是不用下载，随时更新。很适合我这样懒且不追求音质的人。</p>
<p>视频播放器：射手播放器，自动匹配字幕什么的太有爱的，真心离不开。</p>
<p><strong>其它</strong><br />
<a href="http://cleanformac.info/" target="_blank">Clean</a>: 我实在是太喜欢这个小工具了。它能每天定时把桌面上的所有文件移动到Documents文件夹，对于我这个经常能把桌面塞满的人再适合不过了。</p>
<p><a href="http://lembacon.com/dradio/" target="_blank">dRadio</a>: 朋友做的豆瓣电台Mac客户端，UI和功能都无可挑剔，为了这个超赞的软件去用豆瓣电台吧！</p>
<p><a href="http://www.sequelpro.com/" target="_blank">Sequel Pro</a>: 很棒的MySQL管理客户端，phpMyAdmin终于可以删掉了。补充一下，虽然名字里有&#8221;Pro&#8221;，不过人家确实是免费的哦。</p>
<h2>iPhone</h2>
<p>iPhone下除了Reeder ＋ Read it later外简单列举一下我最近常用的软件和游戏：<br />
随手记：记帐很好用，而且借助街旁API提供附近商家功能，借助我查查提供扫描条形码功能，很方便。<br />
Draw Something：超火的游戏。<br />
Game Dev Story：模拟经营游戏，经营一家你自己的游戏公司。虽然画面一般，但就游戏性而言简直就是神作。<br />
Flick Soccer: 扔纸团和足球结合的游戏，限时免费时抢到的，喜欢玩Paper Toss的人不要错过哦。</p>
<p>顺便推荐一个网址收藏服务：<a href="https://kippt.com/" target="_blank">Kippt</a>，功能很简单，帮你收藏并整理你的网址，可惜没有iPhone客户端，不过可以把他们的网站添加到主屏幕上。</p>
]]></content:encoded>
			<wfw:commentRss>http://zihua.li/2012/04/most-commonly-used-software-in-mac-iphone/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>让阅读更轻松，readability for node.js发布</title>
		<link>http://zihua.li/2012/03/node-readability-release/</link>
		<comments>http://zihua.li/2012/03/node-readability-release/#comments</comments>
		<pubDate>Sat, 31 Mar 2012 12:30:50 +0000</pubDate>
		<dc:creator>Luin</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[commonjs]]></category>
		<category><![CDATA[github]]></category>
		<category><![CDATA[module]]></category>
		<category><![CDATA[node.js]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[readability]]></category>

		<guid isPermaLink="false">http://zihua.li/?p=194</guid>
		<description><![CDATA[Readability是从一个开源项目发展而来的产品，该项目托管在Google Code上，不过现在已经不再维护。由于其最初设计在浏览器上运行，在node.js中难以使用，而且转换效果和Readability现在的服务也相差较大。所以这几天我重写了这个项目，具体更新内容附后。 项目托管在Github上。 更新内容 重写代码，增强可读性，更符合node.js书写风格，实现CommonJS标准，并利于服务端调用； 支持GBK, GB2312等编码； 识别/兼容更多的视频网站； 增加提取文章标题功能； 对Wordpress搭建的博客进行特殊处理，效果更好； 性能优化（去除了针对IE浏览器的Hack，并使用了V8的trim函数代替正则表达式等）； 重写计算链接比率的部分，对页内锚点做了修正； 修复会忽略部分网站导航链接的问题； 修复会删除正文中独立img的bug； 增加debug开关； 支持中文标点(readability以标点作为判断正文依据之一)； 增加延迟求值功能，在迭代时速度更快（当不需要文章内容的情况下）； 支持图片、链接的相对路径转换。 TODO 分析文章评论、Tag等; 更多性能提升; 兼容性改进; 增加测试、benchmark。]]></description>
			<content:encoded><![CDATA[<p>Readability是从一个开源项目发展而来的产品，该项目托管在<a href="http://code.google.com/p/arc90labs-readability/" target="_blank">Google Code</a>上，不过现在已经不再维护。由于其最初设计在浏览器上运行，在node.js中难以使用，而且转换效果和Readability现在的服务也相差较大。所以这几天我重写了这个项目，具体更新内容附后。</p>
<p>项目托管在<a href="https://github.com/luin/node-readability" target="_blank">Github</a>上。</p>
<p><img class="size-full wp-image-207 aligncenter" title="readability" src="http://zihua.li/wp-content/uploads/2012/03/readability.jpg" alt="" width="644" height="288" /></p>
<p><strong>更新内容</strong></p>
<ul>
<li>重写代码，增强可读性，更符合node.js书写风格，实现CommonJS标准，并利于服务端调用；</li>
<li>支持GBK, GB2312等编码；</li>
<li>识别/兼容更多的视频网站；</li>
<li>增加提取文章标题功能；</li>
<li>对Wordpress搭建的博客进行特殊处理，效果更好；</li>
<li>性能优化（去除了针对IE浏览器的Hack，并使用了V8的trim函数代替正则表达式等）；</li>
<li>重写计算链接比率的部分，对页内锚点做了修正；</li>
<li>修复会忽略部分网站导航链接的问题；</li>
<li>修复会删除正文中独立img的bug；</li>
<li>增加debug开关；</li>
<li>支持中文标点(readability以标点作为判断正文依据之一)；</li>
<li>增加延迟求值功能，在迭代时速度更快（当不需要文章内容的情况下）；</li>
<li>支持图片、链接的相对路径转换。</li>
</ul>
<p><strong>TODO</strong></p>
<ul>
<li>分析文章评论、Tag等;</li>
<li>更多性能提升;</li>
<li>兼容性改进;</li>
<li>增加测试、benchmark。</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://zihua.li/2012/03/node-readability-release/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>module.exports还是exports？</title>
		<link>http://zihua.li/2012/03/use-module-exports-or-exports-in-node/</link>
		<comments>http://zihua.li/2012/03/use-module-exports-or-exports-in-node/#comments</comments>
		<pubDate>Fri, 30 Mar 2012 08:27:12 +0000</pubDate>
		<dc:creator>Luin</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[commonjs]]></category>
		<category><![CDATA[exports]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[module]]></category>
		<category><![CDATA[node.js]]></category>

		<guid isPermaLink="false">http://zihua.li/?p=180</guid>
		<description><![CDATA[node.js通过实现CommonJS的Modules/1.0标准引入了模块(module)概念，一个模块可以通过module.exports或exports将函数、变量等导出，以使其它JavaScript脚本通过require()函数引入并使用。 现在有一个问题：到底应该用module.exports还是用exports呢？ 最好的方法就是查看node.js的官方文档中关于module的介绍： In particular module.exports is the same as the exports object 可以看出module.exports和exports其实是一样的。在代码里比较： [crayon-4fb8dafb86580/] 输出结果也是true。 然而参照&#8220;module.exports vs exports in nodeJS&#8221;中的例子，考虑下面的代码： [crayon-4fb8dafb8658a/] [crayon-4fb8dafb86592/] [crayon-4fb8dafb865a2/] 执行node b，输出结果如下： {} [Function] 可见a1.js的function导出失败了，而a2却成功了。原因是什么呢？搜索无果后我直接查看了node.js的源代码： [crayon-4fb8dafb865ab/] 这段代码的作用是为global赋属性并调用runInThisContext()函数运行模块(其内容已经事先读入到content变量)。模块中使用的exports(即global.exports)其实是对self.exports的引用，对exports进行修改会影响到self.exports，但如果对其赋值，exports则不再是self.exports的引用了。而对module.exports赋值自然就没有问题。 了解这个，有些node.js模块的源代码中的exports = module.exports = someObject也可以理解了：只使用module.exports = someObject的话module.exports引用的地址变了，而exports引用的还是之前的地址，所以下面的代码中再修改exports就不会再改变module.exports的值了。 总结 养成好习惯，如果不给exports本身赋值的话就用exports.sth = sobj，如果要赋值的话则这样写： [crayon-4fb8dafb865b4/] 更多阅读 CommonJS Modules/1.0 CommonJS的成果之一就是为JavaScript加入了module概念，node.js实现了其中Modules/1.0标准。在这个网站上可以看到其它实现该标准的项目，看看你写的模块还可以在哪个项目里用。 Exports vs module.exports 为数不多的讨论此问题的文章，讲得比较清楚，只是对module.exports和exports的关系没有说到本质，推荐也看看。]]></description>
			<content:encoded><![CDATA[<p>node.js通过实现CommonJS的Modules/1.0标准引入了模块(module)概念，一个模块可以通过module.exports或exports将函数、变量等导出，以使其它JavaScript脚本通过require()函数引入并使用。</p>
<p>现在有一个问题：到底应该用module.exports还是用exports呢？</p>
<p>最好的方法就是查看node.js的<a href="http://nodejs.org/api/modules.html#modules_the_module_object" target="_blank">官方文档中关于module的介绍</a>：</p>
<blockquote><p> In particular module.exports is the same as the exports object</p></blockquote>
<p>可以看出module.exports和exports其实是一样的。在代码里比较：</p><pre class="crayon-plain-tag">console.log(module.exports === exports);</pre><p>输出结果也是true。</p>
<p>然而参照<a href="http://stackoverflow.com/a/7142924" target="_blank">&#8220;module.exports vs exports in nodeJS&#8221;</a>中的例子，考虑下面的代码：</p><pre class="crayon-plain-tag">// a1.js
exports = function () {
  console.log('hi a2!');
}</pre><p></p>
<p></p><pre class="crayon-plain-tag">// a2.js
module.exports = function () {
  console.log('hi a2!');
}</pre><p></p>
<p></p><pre class="crayon-plain-tag">// b.js
console.log(require('./a1'));
console.log(require('./a2'));</pre><p></p>
<p>执行node b，输出结果如下：</p>
<blockquote><p>
{}<br />
[Function]
</p></blockquote>
<p>可见a1.js的function导出失败了，而a2却成功了。原因是什么呢？搜索无果后我直接查看了<a href="https://github.com/joyent/node/blob/master/lib/module.js" target="_blank">node.js的源代码</a>：</p><pre class="crayon-plain-tag">// file path: node/lib/module.js

// ...
global.require = require;
global.exports = self.exports;
global.__filename = filename;
global.__dirname = dirname;
global.module = self;

return runInThisContext(content, filename, true);
// ...</pre><p>这段代码的作用是为global赋属性并调用runInThisContext()函数运行模块(其内容已经事先读入到content变量)。模块中使用的exports(即global.exports)其实是对self.exports的引用，对exports进行修改会影响到self.exports，但如果对其赋值，exports则不再是self.exports的引用了。而对module.exports赋值自然就没有问题。</p>
<p>了解这个，有些node.js模块的源代码中的exports = module.exports = someObject也可以理解了：只使用module.exports = someObject的话module.exports引用的地址变了，而exports引用的还是之前的地址，所以下面的代码中再修改exports就不会再改变module.exports的值了。</p>
<p><strong>总结</strong></p>
<p>养成好习惯，如果不给exports本身赋值的话就用exports.sth = sobj，如果要赋值的话则这样写：</p><pre class="crayon-plain-tag">exports = module.exports = someObject;

exports.sth = sobj; // 如果还需要加入其他属性则这样写</pre><p></p>
<p><strong>更多阅读</strong></p>
<ol>
<li>
<a href="http://wiki.commonjs.org/wiki/Modules/1.0" target="_blank">CommonJS Modules/1.0</a><br />
CommonJS的成果之一就是为JavaScript加入了module概念，node.js实现了其中Modules/1.0标准。在这个网站上可以看到其它实现该标准的项目，看看你写的模块还可以在哪个项目里用。</li>
<li>
<a href="http://www.hacksparrow.com/node-js-exports-vs-module-exports.html" target="_blank">Exports vs module.exports</a><br />
为数不多的讨论此问题的文章，讲得比较清楚，只是对module.exports和exports的关系没有说到本质，推荐也看看。
</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://zihua.li/2012/03/use-module-exports-or-exports-in-node/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>

