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

<channel>
	<title>岁月如歌</title>
	<atom:link href="http://lifesinger.org/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://lifesinger.org/blog</link>
	<description>关注用户体验、前端开发，记录生活点滴、岁月足迹。</description>
	<lastBuildDate>Wed, 03 Feb 2010 04:26:33 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Chrome V8 引擎对 sort 的优化</title>
		<link>http://lifesinger.org/blog/2010/02/chrome-v8-optimization-for-sort/</link>
		<comments>http://lifesinger.org/blog/2010/02/chrome-v8-optimization-for-sort/#comments</comments>
		<pubDate>Wed, 03 Feb 2010 04:25:15 +0000</pubDate>
		<dc:creator>lifesinger</dc:creator>
				<category><![CDATA[前端开发]]></category>
		<category><![CDATA[array]]></category>
		<category><![CDATA[chrome]]></category>
		<category><![CDATA[sort]]></category>
		<category><![CDATA[v8]]></category>

		<guid isPermaLink="false">http://lifesinger.org/blog/?p=2431</guid>
		<description><![CDATA[
var a = 0, b = 0;
[0, 0].sort(function() {
    a = 1;
    return 0;
});
[0, 1].sort(function() {
    b = 1;
    return 0;
});
alert(a === b); // true or false ?

上面的代码，除了 Chrome 输出 false, 其它浏览器皆为 true.
原因是 Chrome 对数组的 sort 方法进行了优化：

function sort(comparefn) {
  var custom_compare = [...]]]></description>
			<content:encoded><![CDATA[<pre>
var a = 0, b = 0;
[0, 0].sort(function() {
    a = 1;
    return 0;
});
[0, 1].sort(function() {
    b = 1;
    return 0;
});
alert(a === b); // true or false ?
</pre>
<p>上面的代码，除了 Chrome 输出 false, 其它浏览器皆为 true.</p>
<p>原因是 Chrome 对数组的 sort 方法进行了优化：</p>
<pre>
function sort(comparefn) {
  var custom_compare = (typeof(comparefn) === 'function');
  function Compare(x,y) {
    if (x === y) return 0;
    if (custom_compare) {
      return comparefn.call(null, x, y);
    }
    ...
}
</pre>
<p>虽然是优化，但也是陷阱。想用 sort 来干点额外体力活时，一定要小心。</p>
]]></content:encoded>
			<wfw:commentRss>http://lifesinger.org/blog/2010/02/chrome-v8-optimization-for-sort/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>JavaScript 全半角转换</title>
		<link>http://lifesinger.org/blog/2010/02/js-sbc2dbc/</link>
		<comments>http://lifesinger.org/blog/2010/02/js-sbc2dbc/#comments</comments>
		<pubDate>Tue, 02 Feb 2010 05:06:29 +0000</pubDate>
		<dc:creator>lifesinger</dc:creator>
				<category><![CDATA[前端开发]]></category>
		<category><![CDATA[dbc]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[sbc]]></category>

		<guid isPermaLink="false">http://lifesinger.org/blog/?p=2426</guid>
		<description><![CDATA[规律：半角空格的 charCode 为 32, 全角空格为 12288. 其他半角字符 ( 33 &#8211; 126 ) 与全角 ( 65281 &#8211; 65374 ) 的对应关系是：均相差 65248.
找好规律，代码就好写了：

var hash = {'32' : '\u3000'};
// 半角转全角
function sbc2dbc(str) {
    var ret = [], i = 0, len = str.length, code, chr;
    for (; i < len; ++i) {
   [...]]]></description>
			<content:encoded><![CDATA[<p>规律：半角空格的 charCode 为 32, 全角空格为 12288. 其他半角字符 ( 33 &#8211; 126 ) 与全角 ( 65281 &#8211; 65374 ) 的对应关系是：均相差 65248.</p>
<p>找好规律，代码就好写了：</p>
<pre>
var hash = {'32' : '\u3000'};
// 半角转全角
function sbc2dbc(str) {
    var ret = [], i = 0, len = str.length, code, chr;
    for (; i < len; ++i) {
        code = str.charCodeAt(i);
        chr = hash[code];
        if (!chr &#038;&#038; code > 31 &#038;&#038; code < 127) {
            chr = hash[code] = String.fromCharCode(code + 65248);
        }
        ret[i] = chr ? chr : str.charAt(i);
    }
    return ret.join('');
}
</pre>
<p><span id="more-2426"></span><br />
同理：</p>
<pre>
var hash = {'12288' : ' '};
// 全角转半角
function dbc2sbc(str) {
    var ret = [], i = 0, len = str.length, code, chr;
    for (; i < len; ++i) {
        code = str.charCodeAt(i);
        chr = hash[code];
        if (!chr &#038;&#038; code > 65280 &#038;&#038; code < 65375) {
            chr = hash[code] = String.fromCharCode(code - 65248);
        }
        ret[i] = chr ? chr : str.charAt(i);
    }
    return ret.join('');
}
</pre>
<p>上面的代码会将 33 - 126 中间的符号也转换。很多时候，这并不是我们需要的（比如将 @ 转换为 ＠）。下面的代码侵入性更小：</p>
<pre>
var hash = {};
// 半角转全角。仅转换 [0-9a-zA-Z]
function sbc2dbc_w(str) {
    var ret = [], i = 0, len = str.length, code, chr;
    for (; i < len; ++i) {
        code = str.charCodeAt(i);
        chr = hash[code];
        if (!chr &#038;&#038;
            (47 < code &#038;&#038; code < 58 ||
             64 < code &#038;&#038; code < 91 ||
             96 < code &#038;&#038; code < 123)) {
            chr = hash[code] = String.fromCharCode(code + 65248);
        }
        ret[i] = chr ? chr : str.charAt(i);
    }
    return ret.join('');
}
</pre>
<p>详细测试页面：<a href="http://lifesinger.googlecode.com/svn/trunk/lab/2010/sbc2dbc-test.html">sbc2dbc-test.html</a></p>
]]></content:encoded>
			<wfw:commentRss>http://lifesinger.org/blog/2010/02/js-sbc2dbc/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Study jQuery in a Simplified Way</title>
		<link>http://lifesinger.org/blog/2010/01/study-jquery-in-a-simplified-way/</link>
		<comments>http://lifesinger.org/blog/2010/01/study-jquery-in-a-simplified-way/#comments</comments>
		<pubDate>Mon, 25 Jan 2010 15:24:27 +0000</pubDate>
		<dc:creator>lifesinger</dc:creator>
				<category><![CDATA[前端开发]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[prototype]]></category>
		<category><![CDATA[push]]></category>
		<category><![CDATA[study]]></category>

		<guid isPermaLink="false">http://lifesinger.org/blog/?p=2419</guid>
		<description><![CDATA[学习复杂代码的最好方法是简化：

(function(win, undefined) {
    var jQuery = function(selector, context) {
            // jQuery 对象就是 init 函数的一个实例
            return new jQuery.fn.init(selector, context);
        },
     [...]]]></description>
			<content:encoded><![CDATA[<p>学习复杂代码的最好方法是简化：</p>
<pre>
(function(win, undefined) {
    var jQuery = function(selector, context) {
            // jQuery 对象就是 init 函数的一个实例
            return new jQuery.fn.init(selector, context);
        },
        document = window.document,
        push = Array.prototype.push,
        slice = Array.prototype.slice;

    jQuery.fn = jQuery.prototype = {
        init: function(selector, context) {
            // 选择器
            var ret = (context || document).querySelectorAll(selector);

            // 转换为普通数组
            ret = slice.call(ret);

            // jQuery API 的奥妙全在下面这句，将选择器获取的元素添加到 jQuery 对象中
            // 使用 push, 速度飞快（当年担心大量 jQuery 对象实例化的性能问题，根本就不是问题）
            // 使用 push, 还能自动更新 length 属性
            push.apply(this, ret);

            return this;
        },
        length: 0,
        // 实例方法
        attr: function(name, value) {
            return access(this, name, value, jQuery.attr);
        }
    };

    // 这句保证了 init 方法里的 this 拥有 jQuery 实例的方法
    jQuery.fn.init.prototype = jQuery.fn;

    // 静态方法
    jQuery.attr = function(elem, name, value) {
        if (value === undefined) {
            return elem.getAttribute(name);
        }
        return elem.setAttribute(name, value);
    };

    // 神奇的 access, 在实例方法和静态方法中建立了一座桥梁
    // 数组批次操作的实现也在这里
    function access(elems, key, value, fn) {
        var length = elems.length;

        if (value !== undefined) {
            for (var i = 0; i < length; i++) {
                fn(elems[i], key, value);
            }
            return elems;
        }

        return length ? fn(elems[0], key) : null;
    }

    win.$ = win.jQuery = jQuery;
})(window);
</pre>
<p>测试页面：<a href="http://lifesinger.googlecode.com/svn/trunk/lab/2010/study-jquery-in-simplified-way.html">study-jquery-in-simplified-way.html</a> （请在非 IE 浏览器下运行）</p>
<p>源码：<a href="http://github.com/jquery/jquery/blob/master/src/core.js">jquery~core.js</a></p>
]]></content:encoded>
			<wfw:commentRss>http://lifesinger.org/blog/2010/01/study-jquery-in-a-simplified-way/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>字符引用和空白字符</title>
		<link>http://lifesinger.org/blog/2010/01/charater-references/</link>
		<comments>http://lifesinger.org/blog/2010/01/charater-references/#comments</comments>
		<pubDate>Mon, 25 Jan 2010 01:33:08 +0000</pubDate>
		<dc:creator>lifesinger</dc:creator>
				<category><![CDATA[前端开发]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[regex]]></category>
		<category><![CDATA[unicode]]></category>
		<category><![CDATA[whitespace]]></category>

		<guid isPermaLink="false">http://lifesinger.org/blog/?p=2411</guid>
		<description><![CDATA[看到最近有讨论，前些日子刚好也收集过一些资料，补充如下：
字符引用
在 html 中，有三种字符引用方式（参考 HTML5 规范）：

Named character references, 通过名称来引用。在 HTML 4.01 中称之为 Character entity references（字符实体引用）比如 &#38;lt; &#38;gt; &#38;nbsp; &#38;quot;, 这里有一份详细列表 named-character-references
Decimal numeric character reference, 通过十进制数值来引用。比如 &#38;#229; &#38;#1048;
Hexadecimal numeric character reference, 通过十六进制数值来引用。比如 &#38;#xe5; &#38;#x6C34;

在 HTML 4.01 中，上面 2 和 3 归为一种：Numeric character references（字符数值引用）。
这里有份非常好的对照表：XHTML Character Entity Reference

在 javascript 中，特殊字符用反斜杠转义，比如 \t, \n, \u0020, 这个不必多说。
在 css 中，只支持 unicode 转义。比如 \0020.
注意：\u0020 [...]]]></description>
			<content:encoded><![CDATA[<p>看到最近有<a href="http://www.99css.com/?p=286">讨论</a>，前些日子刚好也收集过一些资料，补充如下：</p>
<h3>字符引用</h3>
<p>在 html 中，有三种字符引用方式（参考 <a href="http://www.w3.org/TR/html5/syntax.html#character-references">HTML5 规范</a>）：</p>
<ol>
<li>Named character references, 通过名称来引用。在 HTML 4.01 中称之为 Character entity references（字符实体引用）比如 &amp;lt; &amp;gt; &amp;nbsp; &amp;quot;, 这里有一份详细列表 <a href="http://www.w3.org/TR/html5/named-character-references.html">named-character-references</a></li>
<li>Decimal numeric character reference, 通过十进制数值来引用。比如 &amp;#229; &amp;#1048;</li>
<li>Hexadecimal numeric character reference, 通过十六进制数值来引用。比如 &amp;#xe5; &amp;#x6C34;</li>
</ol>
<p>在 HTML 4.01 中，上面 2 和 3 归为一种：Numeric character references（字符数值引用）。<br />
这里有份非常好的对照表：<a href="http://www.digitalmediaminute.com/reference/entity/">XHTML Character Entity Reference</a><br />
<span id="more-2411"></span><br />
在 javascript 中，特殊字符用反斜杠转义，比如 \t, \n, \u0020, 这个不必多说。<br />
在 css 中，只支持 unicode 转义。比如 \0020.<br />
注意：\u0020 在 js 中，必须有 u, 而且必须 4 位。在 css 中，u 必须省略，同时可以省略前导 0. 比如 \0020 在 css 中可以简化为 \20. 因此那个常见的 clearfix, 可以简化为 content: &#8216;\20&#8242;. 好友<a href="http://twitter.com/blankzheng/status/8107822420">怿飞</a>提到的兼容性和语义，应该指的是这个。content 后直接用空格或其它空白字符，会导致某些兼容性问题。</p>
<h3>空白字符</h3>
<p>说到字符引用，不得不提一下空白字符。在 JavaScript 的正则里，\s 是 unicode-aware 的，可以匹配 \u0020, \u0009 等空白字符。但各个浏览器的实现有差异，具体可以参见：<a href="http://blog.stevenlevithan.com/archives/javascript-regex-and-unicode">JavaScript, Regex, and Unicode</a>.</p>
<p>大部分情况下，JS 类库在实现 trim 方法时，使用 /^\s+|\s+$/g 即可。<br />
在 jQuery 中，加入了对 \u00A0 的检测：/^(\s|\u00A0)+|(\s|\u00A0)+$/g<br />
\u00A0 其实就是 &amp;nbsp; 代表 non-breaking space(不间断空白)</p>
<p>关于 &amp;nbsp;, 严格语义上来说，使用场景是不希望自动换行时使用。<br />
但现实中，绝大部分情况下，&amp;nbsp; 就用来表示纯粹的空格。因为多个字符空格在 html 中会被当成一个空格，为了连续输出多个空格，只好用 &amp;nbsp; （毕竟用 css 控制太麻烦）。按理说用多个 &amp;#32; 输出多个空格是最好的选择，但强大的 html 引擎依旧会把多个 &amp;#32; 转换成一个。</p>
<p>jQuery 的 trim 方法加入 \u00A0, 是种无奈，但也是一种对现实标准的认可。</p>
<p>一切皆权衡。</p>
]]></content:encoded>
			<wfw:commentRss>http://lifesinger.org/blog/2010/01/charater-references/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>jQuery 让人恋恋不舍的秘密</title>
		<link>http://lifesinger.org/blog/2010/01/the-beauty-of-jquery-api/</link>
		<comments>http://lifesinger.org/blog/2010/01/the-beauty-of-jquery-api/#comments</comments>
		<pubDate>Tue, 12 Jan 2010 15:41:09 +0000</pubDate>
		<dc:creator>lifesinger</dc:creator>
				<category><![CDATA[前端开发]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[library]]></category>

		<guid isPermaLink="false">http://lifesinger.org/blog/?p=2396</guid>
		<description><![CDATA[jQuery 将马上发布 1.4 正式版，代码也从 googlecode 上迁移到了 github. jQuery 是我接触的第一个 JS 类库，俗话说初恋总是让人难以忘记。一年以前，这种难以忘记仅仅是一种纯感觉，说不出来具体原因。前几天重新看了一遍 github 上的源码。从纯功能上说，jQuery 并没有特别出色的地方。究竟是什么让我如此恋恋不舍呢？
昨天搭建 taskspeed, 检查 jQuery 的测试代码时，突然明晓了一个也许大家都已知道的秘密：
jQuery 最出色最让人恋恋不舍的是它的 API 设计。

比如 dom-style 的 api, YUI3 和 MooTools 等框架采用的是传统方式：

el.setStyle(prop, val);
el.getStyle(prop);
el.setStyles({ propA: valA, propB: valB });
el.getStyles(propA, propB); // MooTools 支持

在 jQuery 里，一个 css 方法全部搞定：

el.css(prop); // 表示 getStyle
el.css(prop, val); // 表示 setStyle
el.css({ propA: valA, propB: valB }); // [...]]]></description>
			<content:encoded><![CDATA[<p>jQuery 将马上发布 1.4 正式版，代码也从 googlecode 上迁移到了 <a href="http://github.com/jquery/jquery">github</a>. jQuery 是我接触的第一个 JS 类库，俗话说初恋总是让人难以忘记。一年以前，这种难以忘记仅仅是一种纯感觉，说不出来具体原因。前几天重新看了一遍 github 上的源码。从纯功能上说，jQuery 并没有特别出色的地方。究竟是什么让我如此恋恋不舍呢？</p>
<p>昨天搭建 <a href="http://lifesinger.org/labs/taskspeed/">taskspeed</a>, 检查 jQuery 的测试代码时，突然明晓了一个也许大家都已知道的秘密：</p>
<p><strong>jQuery 最出色最让人恋恋不舍的是它的 API 设计。</strong><br />
<span id="more-2396"></span><br />
比如 dom-style 的 api, YUI3 和 MooTools 等框架采用的是传统方式：</p>
<pre>
el.setStyle(prop, val);
el.getStyle(prop);
el.setStyles({ propA: valA, propB: valB });
el.getStyles(propA, propB); // MooTools 支持
</pre>
<p>在 jQuery 里，一个 css 方法全部搞定：</p>
<pre>
el.css(prop); // 表示 getStyle
el.css(prop, val); // 表示 setStyle
el.css({ propA: valA, propB: valB }); // 表示 setStyles
el.css(prop, func); // func 是一个返回 val 值的函数
</pre>
<p>对比以上两种 API 设计，乍一看 jQuery 显得不那么“标准”。但从可记忆性和灵活性上讲，我觉得 jQuery 的设计都更人性化。jQuery 的 API 还符合学习上的渐进式思维：先学会最简单的情况<code>el.css(prop)</code>, 再了解到还可以有两个参数，接着发现参数可以是 map, 更进一步发现 val 还可以是一个函数。func 参数甚至能带给学习者一种惊喜：居然还可以这样用！jQuery 把一种渐进和愉悦带进了学习和使用的过程中，实在漂亮！</p>
<p>YUI3 的 API 缺少这种乐趣。查询 jQuery 的 API, 会有一种探寻秘密的寻宝感觉。YUI 的文档查询则让人感觉就是份工作，有点 boring.</p>
<p>和 YUI2 相比，YUI3 的 API 做了些改变。在 YUI2 里，YAHOO.util.Dom 的方法名，严格以动词开头，虽然有些方法名长点，但总体规律性很强，可记忆性还不错。在 YUI3 里，则出现了 byId, elementByAxis 等方式命名的方法。纯粹为了省几个字符？这种不一致性很纳闷。还有一些以名词命名的方法：ancestor, docHeight, 乍一看很难以为是方法。</p>
<p>老婆说，要睡觉了，就不码字了。最后说一句：YUI3 的 API 整体还是挺不错的，比如 Node 的方法命名，就非常严谨。ancestor 也是为了对应 next, prev 等命名。也就是说：Y.Dom 其实已变成了内部 API, 不鼓励用户直接调用。</p>
<p>但是不知为什么，我还是觉得 jQuery 的 API 设计高出一个层次，套用一句流行话就是：<br />
<strong>jQuery API 的用户体验更好。</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://lifesinger.org/blog/2010/01/the-beauty-of-jquery-api/feed/</wfw:commentRss>
		<slash:comments>32</slash:comments>
		</item>
		<item>
		<title>The Deferred Evaluation of YUI 3</title>
		<link>http://lifesinger.org/blog/2010/01/the-deferred-evaluation-of-yui3/</link>
		<comments>http://lifesinger.org/blog/2010/01/the-deferred-evaluation-of-yui3/#comments</comments>
		<pubDate>Tue, 12 Jan 2010 02:08:47 +0000</pubDate>
		<dc:creator>lifesinger</dc:creator>
				<category><![CDATA[前端开发]]></category>
		<category><![CDATA[defer]]></category>
		<category><![CDATA[evaluation]]></category>

		<guid isPermaLink="false">http://lifesinger.org/blog/?p=2391</guid>
		<description><![CDATA[JS 的加载速度，包括下载和运算两部分（参考 JavaScript Library Loading Speed）：

Total_Speed = Time_to_Download + Time_to_Evaluate

运算（evaluate）又可细分为解析（parse）和执行（execute）。考虑加载速度时，一般放在一起考虑。
通常来说，下载时间是影响 JS 加载速度的关键。这方面的优化已经很成熟，比如 Compressor, GZip, Cache 等等。
evaluation 部分，目前主要优化方案是延迟（称之 Deferred Evaluation）。具体策略有：

将 JS 代码以注释的形式下载，需要使用时再 parse. 可以参考 GMail for Mobile Team 的研究。
将 JS 代码以字符串定义的形式下载。可以参考 SproutCore Blog 的分析。
将 JS 代码以闭包的形式下载。

第一种策略能将 evaluation 完全延迟，后两种还存在少量未被延迟的 evaluation, 但和第一种差异很小。下面讨论第三种。

YUI 3
YUI 3 的模块定义代码：

YUI.add("module-a", function(Y) {
    /* module code */
});

模块添加到 YUI 上时，function(Y)作为一个整体(closure)注册到环境变量里，module code 尚未执行。
模块调用代码：

YUI().use("module-a", [...]]]></description>
			<content:encoded><![CDATA[<p>JS 的加载速度，包括下载和运算两部分（参考 <a href="http://ejohn.org/blog/library-loading-speed/">JavaScript Library Loading Speed</a>）：</p>
<blockquote><p>
Total_Speed = Time_to_Download + Time_to_Evaluate
</p></blockquote>
<p>运算（evaluate）又可细分为解析（parse）和执行（execute）。考虑加载速度时，一般放在一起考虑。</p>
<p>通常来说，下载时间是影响 JS 加载速度的关键。这方面的优化已经很成熟，比如 Compressor, GZip, Cache 等等。</p>
<p>evaluation 部分，目前主要优化方案是延迟（称之 Deferred Evaluation）。具体策略有：</p>
<ol>
<li>将 JS 代码以注释的形式下载，需要使用时再 parse. 可以参考 <a href="http://googlecode.blogspot.com/2009/09/gmail-for-mobile-html5-series-reducing.html">GMail for Mobile Team</a> 的研究。</li>
<li>将 JS 代码以字符串定义的形式下载。可以参考 <a href="http://feedproxy.google.com/~r/Sproutcore-BlogPosts/~3/-0S1tX1vtN0/225219087">SproutCore Blog</a> 的分析。</li>
<li>将 JS 代码以闭包的形式下载。</li>
</ol>
<p>第一种策略能将 evaluation 完全延迟，后两种还存在少量未被延迟的 evaluation, 但和第一种差异很小。下面讨论第三种。<br />
<span id="more-2391"></span></p>
<h3>YUI 3</h3>
<p>YUI 3 的模块定义代码：</p>
<pre>
YUI.add("module-a", function(Y) {
    /* module code */
});
</pre>
<p>模块添加到 YUI 上时，<code>function(Y)</code>作为一个整体(closure)注册到环境变量里，module code 尚未执行。</p>
<p>模块调用代码：</p>
<pre>
YUI().use("module-a", function(Y) {
    /* user code */
});
</pre>
<p>此时，定义代码中的 function closure 才被调用：执行 module code, 将 module a 挂载到 YUI 的实例 Y 上。</p>
<p>很显然，YUI 3 的模块定义和加载机制，非常自然地实现了 Deferred Evaluation 的第三种策略。我们来看看效果如何。</p>
<h3>Tests</h3>
<p>测试页面：<a href="http://lifesinger.googlecode.com/svn/trunk/lab/2010/faster-javascript-load/test.html">deferred evaluation test</a></p>
<p>测试方法：点击 Load YUI3 按钮，会看到第二个 iframe 重复加载 5 次。加载完成后，点击 iframe 里的 Run Again （确保有缓存）。结果里的 Setup time &#8211; Load time, 就是 Deferred Evaluation 能为页面减少的加载时间。</p>
<p><img src="http://lifesinger.googlecode.com/svn/trunk/lab/2010/faster-javascript-load/yui3-deferred-evaluation.png" alt="YUI3 Deferred Evaluation Chart" /><br />
上图是在 T61 上的测试结果。加载的 JS 文件是 <a href="http://lifesinger.googlecode.com/svn/trunk/lab/2010/yui3-performance-test/yui3-combo-min.js">yui3-combo-min.js</a>, 仅打包了 YUI3 的基础模块。</p>
<p>从结果上可以看出，对于普通电脑来说，Deferred Evaluation 带来的性能提升并不明显：差异最大的 Safari 上，也仅减少了不到 50ms. 但可以推测：电脑 CPU 越低，Deferred Evaluation 带来的提升会越明显，比如 Mobile 应用上。</p>
<h3>结论</h3>
<ol>
<li>对于 YUI 3 来说，这是沙箱和模块加载机制带来的意外惊喜：能减少初始加载时间总是好的，虽然微不足道。</li>
<li>对于 Mobile 应用来说，Deferred Evaluation 非常值得尝试，Gmail for Mobile 团队走在了前列。</li>
<li>对于普通 Web 应用来说，JS 加载的主要性能优化点依旧是减少文件本身的大小，比如将 YUI Compressor 换成 Google Closure Compiler.</li>
</ol>
<p>最后推荐 Ara Pehlivanian 的博文：<a href="http://www.phpied.com/javascript-loading-strategies/">JavaScript loading strategies</a>, JS 加载有五个方面的优化策略：Reduce(减少文件大小), Defer(延迟), Go Async(异步), Be Lazy(懒加载), Bite Size(真的需要 JS 吗)，这五点特别是最后一点，需要我们的坚持和努力。</p>
]]></content:encoded>
			<wfw:commentRss>http://lifesinger.org/blog/2010/01/the-deferred-evaluation-of-yui3/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>JavaScript 框架的 DOM 操作性能</title>
		<link>http://lifesinger.org/blog/2010/01/jslib-dom-performance-test/</link>
		<comments>http://lifesinger.org/blog/2010/01/jslib-dom-performance-test/#comments</comments>
		<pubDate>Mon, 11 Jan 2010 04:25:51 +0000</pubDate>
		<dc:creator>lifesinger</dc:creator>
				<category><![CDATA[前端开发]]></category>
		<category><![CDATA[DOM]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[taskspeed]]></category>
		<category><![CDATA[YUI]]></category>
		<category><![CDATA[YUI3]]></category>

		<guid isPermaLink="false">http://lifesinger.org/blog/?p=2389</guid>
		<description><![CDATA[经克军提醒，在博客上也搭建了个 TaskSpeed: 
http://lifesinger.org/labs/taskspeed/
将感兴趣的框架都更新到最新版本。修改了部分 tests.js, 以保证主流浏览器下所有用例都能得到正确结果。
特别修改了 YUI 2.8 的测试文件：yui-tests.js. 原测试文件大量使用YAHOO.util.Selector这个并不推荐使用的类，不符合 YUI 2 的实际使用情况（一般仅使用 yahoo-dom-event, get, anim 等 utilities）。
从测试结果可以看出：
前三甲是 Dojo 1.4, jQuery 1.4, YUI 2.8
MooTools 在 Safari 下表现优异，其它浏览器下有些惨淡。
Prototype 老矣，尚能饭否？
YUI 3 中规中矩，不出色，但也不糟糕。
]]></description>
			<content:encoded><![CDATA[<p>经<a href="http://hikejun.com/">克军</a>提醒，在博客上也搭建了个 TaskSpeed: </p>
<p><a href="http://lifesinger.org/labs/taskspeed/">http://lifesinger.org/labs/taskspeed/</a></p>
<p>将感兴趣的框架都更新到最新版本。修改了部分 tests.js, 以保证主流浏览器下所有用例都能得到正确结果。</p>
<p>特别修改了 YUI 2.8 的测试文件：<a href="http://lifesinger.org/labs/taskspeed/tests/yui-tests.js">yui-tests.js</a>. 原测试文件大量使用<code>YAHOO.util.Selector</code>这个并不推荐使用的类，不符合 YUI 2 的实际使用情况（一般仅使用 yahoo-dom-event, get, anim 等 utilities）。</p>
<p>从测试结果可以看出：</p>
<p>前三甲是 Dojo 1.4, jQuery 1.4, YUI 2.8<br />
MooTools 在 Safari 下表现优异，其它浏览器下有些惨淡。<br />
Prototype 老矣，尚能饭否？<br />
YUI 3 中规中矩，不出色，但也不糟糕。</p>
]]></content:encoded>
			<wfw:commentRss>http://lifesinger.org/blog/2010/01/jslib-dom-performance-test/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Fastest JavaScript Trim</title>
		<link>http://lifesinger.org/blog/2010/01/fastest-javascript-trim/</link>
		<comments>http://lifesinger.org/blog/2010/01/fastest-javascript-trim/#comments</comments>
		<pubDate>Sun, 10 Jan 2010 14:55:14 +0000</pubDate>
		<dc:creator>lifesinger</dc:creator>
				<category><![CDATA[前端开发]]></category>

		<guid isPermaLink="false">http://lifesinger.org/blog/?p=2384</guid>
		<description><![CDATA[这是 2007 年的一篇老文：Faster JavaScript Trim.
测试页面：trim-test.html
感兴趣的几个方法：

function trim1(str) {
    return str.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
}
function trim2(str) {
    return str.replace(/^\s+/, '').replace(/\s+$/, '');
}
function trim4(str) {
    return str.replace(/^\s+&#124;\s+$/g, '');
}
function trim8(str) {
    return str.replace(/^\s*((?:[\S\s]*\S)?)\s*$/, '$1');
}

时至今日，有些结论已经发生变化：

1. trim1 中使用的正则优化：pre-check of required character and start of string anchor, 在最新的 JS 引擎中已经内置。trim4 也得到了非常好的优化，比 trim1, trim2 [...]]]></description>
			<content:encoded><![CDATA[<p>这是 2007 年的一篇老文：<a href="http://blog.stevenlevithan.com/archives/faster-trim-javascript">Faster JavaScript Trim</a>.</p>
<p>测试页面：<a href="http://lifesinger.googlecode.com/svn/trunk/lab/2010/trim-test.html">trim-test.html</a></p>
<p>感兴趣的几个方法：</p>
<pre>
function trim1(str) {
    return str.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
}
function trim2(str) {
    return str.replace(/^\s+/, '').replace(/\s+$/, '');
}
function trim4(str) {
    return str.replace(/^\s+|\s+$/g, '');
}
function trim8(str) {
    return str.replace(/^\s*((?:[\S\s]*\S)?)\s*$/, '$1');
}
</pre>
<p>时至今日，有些结论已经发生变化：<br />
<span id="more-2384"></span><br />
1. trim1 中使用的正则优化：pre-check of required character and start of string anchor, 在最新的 JS 引擎中已经内置。trim4 也得到了非常好的优化，比 trim1, trim2 都快。</p>
<p>2. trim8 在 IE 中依旧非常有优势。这是因为 IE 对 \S\s (any character token) 有非常好的优化。另外 ?: (non-capturing group) 对性能也有提升。</p>
<p>3. trim10 是非正则实现方案，速度飕飕的。原文中指出关键点：正则在处理过程中无法直接跳转到字符串末尾，从而导致在处理长字符串时耗时稍长。于是有了混合版本 trim11 和 trim11 的改进版本 trim12:</p>
<pre>
function trim11(str) {
    str = str.replace(/^\s+/, '');
    for (var i = str.length - 1; i >= 0; i--) {
        if (/\S/.test(str.charAt(i))) {
            str = str.substring(0, i + 1);
            break;
        }
    }
    return str;
}

function trim12(str) {
    str = str.replace(/^\s\s*/, "");
    var ws = /\s/,
            i = str.length;
    while (ws.test(str.charAt(--i))) {}
    return str.slice(0, i + 1);
}
</pre>
<p>4. 在原文的回复中，还有利用空间换时间的 map 方案。</p>
<p>5. 对于普通应用，比如 JS 框架，原文作者推荐使用 trim1. 从上面的变化可以看出，目前更好的方案是 trim4. 这也正是当今流行 JS 框架中广泛采用的实现方案。对于特殊应用需要处理长字符串时，推荐采用 trim11.</p>
<p>6. 目前 Firefox 3 和 Chrome 4 中都已原生实现 String.prototype.trim, 对于这些浏览器，原生实现始终是最佳方案。</p>
<p>7. 原文作者的 final note 值得注意：许多开发者习惯用变量缓存正则，这可以避免正则的重复编译，但这对于简单如 trim 的正则来说意义不大。trim 的正则如此简单，编译时间是纳秒级的。而且不少浏览器自身已对最近使用的正则进行缓存，不会存在重复编译的问题。trim13 用来验证此观点，除了 IE, 其它浏览器下，当重复次数 times 变大时，trim13 反而比 trim12 略有优势。</p>
<p>8. 讨论一个有争议的点：对于 JS 类库来说，trim 方法究竟应不应该附加在 String.prototype 上呢？侵入 built-in 对象，会导致<code>for...in</code>产生<a href="https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Statements/for...in">某些非预期结果</a>。但是，对于 String 来说，用<code>for...in</code>遍历 String 本就是非常不明智的行为。为了这些“愚蠢的”使用方法，而坚决不侵入 built-in 对象，是否真的值得？毕竟从用户角度讲，<code>str.trim()</code> ，比类似<code>$.trim(str)</code>这种写法自然多了。</p>
<p>最后给一个我的方案：</p>
<pre>
if(!String.prototype.trim) {
    var TRIM_REG = /^\s+|\s+$/g;
    String.prototype.trim = function() { return this.replace(TRIM_REG, ''); }
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://lifesinger.org/blog/2010/01/fastest-javascript-trim/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>YUI3 DOM Manipulation Performance Test</title>
		<link>http://lifesinger.org/blog/2010/01/yui3-dom-manipulation-performance-test/</link>
		<comments>http://lifesinger.org/blog/2010/01/yui3-dom-manipulation-performance-test/#comments</comments>
		<pubDate>Sun, 10 Jan 2010 09:00:08 +0000</pubDate>
		<dc:creator>lifesinger</dc:creator>
				<category><![CDATA[前端开发]]></category>
		<category><![CDATA[DOM]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[YUI3]]></category>

		<guid isPermaLink="false">http://lifesinger.org/blog/?p=2373</guid>
		<description><![CDATA[测试场景：给 table 的 150 个 tr 添加style="color: #ccc", 重复 20 次。
测试页面：dom-manipulation.html
点击每个测试按钮前，都重新启动浏览器。手工记录 10 * 4 * 4 次无明显偏差的数据，取平均值，可得到以下统计结果：

其它 DOM 操作结果类似。
结论：当页面较复杂，DOM 操作较多时，YUI3 会明显增加脚本执行时间，存在性能隐患。

原因分析
测试代码：

// jQuery 1.4
$("#test-table tr").css("color", "#ccc");

// YUI 3
Y.all("#test-table tr").setStyle("color", "#ccc");

用 Firebug 跟踪调用：
jQuery 基本调用链为：Sizzle &#8211; access(让 collection 有 css 方法) &#8211; css.
YUI 3 的调用链更复杂，甚至出现了 docHeight() 方法的调用。阅读源码可推测基本调用链为：Query &#8211; NodeList &#8211; Node &#8211; setStyle.
可以看出执行性能有三个方面：选择器性能、内部调用过程 和 setStyle 原子操作性能。
对于选择器来说，简单如#test-table tr, 经测试两者相差很小。
纯 [...]]]></description>
			<content:encoded><![CDATA[<p>测试场景：给 table 的 150 个 tr 添加<code>style="color: #ccc"</code>, 重复 20 次。<br />
测试页面：<a href="http://lifesinger.googlecode.com/svn/trunk/lab/2010/yui3-performance-test/dom-manipulation.html">dom-manipulation.html</a></p>
<p>点击每个测试按钮前，都重新启动浏览器。手工记录 10 * 4 * 4 次无明显偏差的数据，取平均值，可得到以下统计结果：<br />
<img width="550" height="319" src="http://lifesinger.googlecode.com/svn/trunk/lab/2010/yui3-performance-test/dom-manipulation-spent-time-comparison.png" alt="dom manipulation spent time comparison chart" /></p>
<p>其它 DOM 操作结果类似。</p>
<p>结论：当页面较复杂，DOM 操作较多时，YUI3 会明显增加脚本执行时间，存在性能隐患。<br />
<span id="more-2373"></span></p>
<h4>原因分析</h4>
<p>测试代码：</p>
<pre>
// jQuery 1.4
$("#test-table tr").css("color", "#ccc");

// YUI 3
Y.all("#test-table tr").setStyle("color", "#ccc");
</pre>
<p>用 Firebug 跟踪调用：<br />
jQuery 基本调用链为：Sizzle &#8211; access(让 collection 有 css 方法) &#8211; css.<br />
YUI 3 的调用链更复杂，甚至出现了 docHeight() 方法的调用。阅读源码可推测基本调用链为：Query &#8211; NodeList &#8211; Node &#8211; setStyle.</p>
<p>可以看出执行性能有三个方面：选择器性能、内部调用过程 和 setStyle 原子操作性能。</p>
<p>对于选择器来说，简单如<code>#test-table tr</code>, 经测试两者相差很小。<br />
纯 setStyle 操作，两者也差不多。<br />
可以判断：性能差异来自内部调用过程的设计。</p>
<h4>思考</h4>
<p>YUI3 的整体设计很漂亮，体现了 scalable（可大可小，能适用于小型站点也能搭建大型复杂应用） 的愿景。但这个 scalable 特性，目前看起来，仅体现在代码的模块组织以及灵活的组件加载和沙箱机制上。对于代码功能本身来说，YUI3 是个庞然大物。简单的功能，也需要历经设计优雅但执行漫长的内部调用过程。</p>
<p>感觉 YUI3 实际走向的是 ExtJS 路线。对于小型站点和快速应用来说，还是 jQuery 和 YUI2 好使。</p>
]]></content:encoded>
			<wfw:commentRss>http://lifesinger.org/blog/2010/01/yui3-dom-manipulation-performance-test/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>重构之美 &#8211; Switchable 组件开发心得</title>
		<link>http://lifesinger.org/blog/2010/01/the-beauty-of-refactoring/</link>
		<comments>http://lifesinger.org/blog/2010/01/the-beauty-of-refactoring/#comments</comments>
		<pubDate>Tue, 05 Jan 2010 12:19:14 +0000</pubDate>
		<dc:creator>lifesinger</dc:creator>
				<category><![CDATA[前端开发]]></category>
		<category><![CDATA[carousel]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[KISSY]]></category>
		<category><![CDATA[refactoring]]></category>
		<category><![CDATA[slide]]></category>
		<category><![CDATA[switchable]]></category>
		<category><![CDATA[tabs]]></category>

		<guid isPermaLink="false">http://lifesinger.org/blog/?p=2366</guid>
		<description><![CDATA[slideshare 在线观看：The Beauty Of Refactoring
ppt 下载：重构之美.pptx
src code：/trunk/src/widget-switchable

欢迎讨论交流。
]]></description>
			<content:encoded><![CDATA[<p>slideshare 在线观看：<a href="http://www.slideshare.net/lifesinger/the-beauty-of-refactoring">The Beauty Of Refactoring</a><br />
ppt 下载：<a href="http://lifesinger.googlecode.com/svn/trunk/share/2010/201001_重构之美.pptx">重构之美.pptx</a><br />
src code：<a href="http://kissy.googlecode.com/svn/trunk/src/widget-switchable/">/trunk/src/widget-switchable</a><br />
<img src="http://lifesinger.org/blog/wp-content/uploads/2010/01/the-beauty-of-refactoring.jpg" alt="the beauty of refactoring" /><br />
欢迎讨论交流。</p>
]]></content:encoded>
			<wfw:commentRss>http://lifesinger.org/blog/2010/01/the-beauty-of-refactoring/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
	</channel>
</rss>
