<?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>I&#039;m Png</title>
	<atom:link href="http://www.impng.com/feed" rel="self" type="application/rss+xml" />
	<link>http://www.impng.com</link>
	<description>重要的不只是技术，关注的不仅是前端</description>
	<lastBuildDate>Fri, 02 Dec 2011 01:23:37 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>js并行加载，顺序执行</title>
		<link>http://www.impng.com/web-dev/parallel-download-ordered-execute.html</link>
		<comments>http://www.impng.com/web-dev/parallel-download-ordered-execute.html#comments</comments>
		<pubDate>Thu, 01 Dec 2011 16:47:02 +0000</pubDate>
		<dc:creator>damon</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[ControlJS]]></category>
		<category><![CDATA[execution order]]></category>
		<category><![CDATA[LABjs]]></category>
		<category><![CDATA[maintain ordering]]></category>
		<category><![CDATA[non-blocking]]></category>
		<category><![CDATA[parallel download]]></category>
		<category><![CDATA[保持执行顺行]]></category>
		<category><![CDATA[并行加载]]></category>
		<category><![CDATA[非阻塞]]></category>

		<guid isPermaLink="false">http://www.impng.com/?p=500</guid>
		<description><![CDATA[&#60;script&#62;运行脚本或加载外部文件时，会阻塞页面渲染，阻塞其他资源的加载。如果页面中需要加载多个js文件，在古老浏览器中性能会比较糟糕。 因此有了最原始的优化原则：把脚本放在底部。 如何实现js非阻塞、并行加载，甚至能保持执行顺序呢？各浏览器表现如何？站在巨人的肩膀上，Kyle Simpson、Nicholas C. Zakas和Steve Souders对此有过总结和方案。 背景 1. Script DOM Element。 动态插入&#60;script&#62;，不会阻塞，但无法保持执行顺序。但唯有Firefox可以保持执行顺序，但也差点在Firefox 4 nightly的版本中去掉这个特性。 2. HTML5 async 非阻塞，加载完后立即执行，不保证顺序。这个属性不管有没有值、值为true或false，都是等同的效果（由于Kyle的推进，不能保证执行顺序与其值无关了）。 Google Analytics的新版嵌入代码就结合使用了上面两个方案，如： var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); 3. IE defer属性。不阻塞，可以保证顺序，在DOM加载完成后执行（在DOMContentLoaded之前）。 4. &#60;script&#62;的type属性设为&#8221;script/cache&#8221; 非标准的type属性，使js文件只会被加载而不会执行。需要执行时，创建一个type属性为&#8221;text/javascript&#8221;的正常&#60;script&#62;元素，src设为前面已经加载的js地址即可，执行顺序开发者可控（执行时机也完全可控）。类似的方式也有通过&#60;img&#62;来做预加载的。 5. [...]]]></description>
			<content:encoded><![CDATA[<p>&lt;script&gt;运行脚本或加载外部文件时，会阻塞页面渲染，阻塞其他资源的加载。如果页面中需要加载多个js文件，在古老浏览器中性能会比较糟糕。 因此有了最原始的优化原则：<a href="http://www.impng.com/web-dev/put-script-at-the-bottom-read-notes.html">把脚本放在底部</a>。</p>
<p>如何实现js非阻塞、并行加载，甚至能保持执行顺序呢？各浏览器表现如何？站在巨人的肩膀上，<a href="http://blog.getify.com/">Kyle Simpson</a>、<a href="http://www.nczonline.net/">Nicholas C. Zakas</a>和<a href="http://www.stevesouders.com/">Steve Souders</a>对此有过总结和方案。</p>
<h2>背景</h2>
<p>1. Script DOM Element。 动态插入&lt;script&gt;，不会阻塞，但无法保持执行顺序。但唯有Firefox可以保持执行顺序，但也差点在Firefox 4 nightly的版本中去掉这个特性。</p>
<p>2. HTML5 async 非阻塞，加载完后立即执行，不保证顺序。这个属性不管有没有值、值为true或false，都是等同的效果（由于Kyle的推进，不能保证执行顺序与其值无关了）。</p>
<p>Google Analytics的新版嵌入代码就结合使用了上面两个方案，如：</p>
<pre class="brush:js">
var ga = document.createElement('script');
ga.type = 'text/javascript';
ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www')
          + '.google-analytics.com/ga.js';

var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
</pre>
<p>3. IE defer属性。不阻塞，可以保证顺序，在DOM加载完成后执行（在DOMContentLoaded之前）。</p>
<p>4. &lt;script&gt;的type属性设为&#8221;script/cache&#8221; 非标准的type属性，使js文件只会被加载而不会执行。需要执行时，创建一个type属性为&#8221;text/javascript&#8221;的正常&lt;script&gt;元素，src设为前面已经加载的js地址即可，执行顺序开发者可控（执行时机也完全可控）。类似的方式也有通过&lt;img&gt;来做预加载的。</p>
<p>5. document.write。文档流关闭后执行会清空整个页面。</p>
<p>6. XHR 并行加载，执行顺序可控，但有同域限制。</p>
<h2>基本需求</h2>
<p>Steve Souders 和 Nicholas C. Zakas 一起总结了下，认为<a href="http://www.nczonline.net/blog/2010/12/21/thoughts-on-script-loaders/">js加载方案必须解决以下问题</a>：</p>
<ol>
<li>支持特性检测</li>
<li>不会重复加载</li>
<li>支持并行加载</li>
</ol>
<h2>开发者的美好愿望</h2>
<p>Nicholas C. Zakas 几经周折，有了以下的提案，<a href="http://www.nczonline.net/blog/2011/02/14/separating-javascript-download-and-execution/">分离js的加载和执行</a>，方便开发者自由控制js的执行时间。</p>
<pre class="brush:javascript">
var script = document.createElement("script");

// 此属性仅可由js动态写入，在HTML标签中直接写入无效
script.preload = true;

// src赋值后，立即触发加载（仅加载，不会执行js内容）
script.src = "foo.js";

// onpreload是需要新支持的事件，加载完成后触发此事件
script.onpreload = function(){
    // 在需要时，将加载的js插入到DOM中，即可运行生效
    document.body.appendChild(script);
};
</pre>
<p>基于特性检测feature detection（区别于特性推测feature inference）</p>
<p class="code">var isPreloadSupported = (typeof script.preload == &#8220;boolean&#8221;);</p>
<p>这一特性只有在Javascript中动态赋值时生效，直接写到HTML标签上时是无效的。</p>
<p>但这只是一个提案，开发者们的美好愿望，而非被浏览器支持的标准。目前这一提案已在LABjs中支持，Zakas本人也在积极推进此提案的标准化。</p>
<p>而Kyle在推进另外一种方式，即要求<a href="http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order#My_Solution">对含有属性async=false的&lt;script&gt;保持执行顺序</a>。如果async=true，则一旦加载完则会马上执行脚本，不会严格保持顺序。默认地，页面中的&lt;script&gt;的async属性为false，即保持执行顺序；js创建的&lt;script&gt;的async属性为true，即加载完立即执行，不保证顺序。</p>
<p>为了支持特性检测，一个由js创建的&lt;script&gt;标签默认具有async=true的属性。</p>
<p><a href="https://www.w3.org/Bugs/Public/show_bug.cgi?id=11295">Kyle的这一提案已被HTML5小组接受放入草案</a>，在Firefox 4 nightly版本中的也已实现。</p>
<p>Firefox 4为了更向HTML5标准看齐，一度在<a href="https://developer.mozilla.org/en/Firefox_4_for_developers#Miscellaneous_DOM_changes">开发者版本中去掉了对动态创建&lt;script&gt;来加载js文件的执行顺序支持</a>：</p>
<blockquote><p>
&lt;script&gt; elements created using document.createElement() and inserted into a document now behave according to the HTML5 specification by default. Scripts with the src attribute execute as soon as available (without maintaining ordering) and scripts without the src attribute execute synchronously.
</p></blockquote>
<p>为此，<a href="https://bugs.webkit.org/show_bug.cgi?id=50115">Kyle向WebKit开发团队抗议，提了一个bug</a>，最终得到了如他所愿的支持：</p>
<blockquote><p>
To make script-inserted scripts that have the src attribute execute in the insertion order, set .async=false on them.
</p></blockquote>
<p>Zakas很欣赏Kyle的方案，Kyle在LABjs中也支持了Zakas的提议，各浏览器们也这么和谐就好了。</p>
<h2>现有解决方案</h2>
<p><strong><a href="http://labjs.com/">LABJS</a></strong><br />
作者：Kyle Simpson<br />
特点：并行加载，并保持顺序<br />
主要方案：async=false、preonload新提案的支持，以及兼容各浏览器的方案，维护成本不小。</p>
<p><strong><a href="http://stevesouders.com/controljs/">ControlJS</a></strong><br />
作者：Steve Souders<br />
特点：并行加载，无顺序保证<br />
主要方案：&lt;script type=&#8221;text/cache&#8221;&gt;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.impng.com/web-dev/parallel-download-ordered-execute.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>HTML(5) 不要求标签自闭合</title>
		<link>http://www.impng.com/web-dev/html-tags-without-self-closing.html</link>
		<comments>http://www.impng.com/web-dev/html-tags-without-self-closing.html#comments</comments>
		<pubDate>Tue, 22 Nov 2011 14:56:19 +0000</pubDate>
		<dc:creator>damon</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[html5]]></category>
		<category><![CDATA[self-closing]]></category>
		<category><![CDATA[自闭合]]></category>

		<guid isPermaLink="false">http://www.impng.com/?p=484</guid>
		<description><![CDATA[XHTML教导我们，标签都是要闭合的，不能包含子元素的标签需要自闭合。但HTML5是没有这个要求的，所有HTML中都没这个要求，是XHTML将这门松散的语言变得严格起来。XHTML诸多严格，包括标签都要闭合，包括tagName和属性都要小写等。 HTML 第一版 追溯HTML的元祖第一版，就是不要求自闭合的，如下的一段用法就表明了其的松散随意 &#60;ADDRESS&#62; Newsletter editor&#60;p&#62; J.R. Brown&#60;p&#62; JimquickPost News, Jumquick, CT 01234&#60;p&#62; Tel (123) 456 7890 &#60;/ADDRESS&#62; 对于&#60;img&#62;这类标签，本来就是没有闭合的，原始定义为： The IMG element is empty: it has no closing tag. 现行的 HTML5 HTML5中，&#60;br&#62; &#60;img&#62; &#60;input&#62; &#60;meta&#62;等空标签可以不用自闭合了。 官方草案中描述： Then, if the element is one of the void elements, or if the element is a foreign element, [...]]]></description>
			<content:encoded><![CDATA[<p>XHTML教导我们，标签都是要闭合的，不能包含子元素的标签需要自闭合。但HTML5是没有这个要求的，所有HTML中都没这个要求，是XHTML将这门松散的语言变得严格起来。XHTML诸多严格，包括标签都要闭合，包括tagName和属性都要小写等。</p>
<h2>HTML 第一版</h2>
<p>追溯HTML的<a href="http://www.w3.org/MarkUp/draft-ietf-iiir-html-01.txt">元祖第一版</a>，就是不要求自闭合的，如下的一段用法就表明了其的松散随意</p>
<pre class="brush:html">&lt;ADDRESS&gt;
Newsletter editor&lt;p&gt;
J.R. Brown&lt;p&gt;
JimquickPost News, Jumquick, CT 01234&lt;p&gt;
Tel (123) 456 7890
&lt;/ADDRESS&gt;</pre>
<p>对于&lt;img&gt;这类标签，本来就是没有闭合的，原始定义为：</p>
<p><strong>The IMG element is empty: it has no closing tag.</strong></p>
<h2>现行的 HTML5</h2>
<p>HTML5中，&lt;br&gt; &lt;img&gt; &lt;input&gt; &lt;meta&gt;等空标签可以不用自闭合了。</p>
<p><a href="http://www.whatwg.org/specs/web-apps/current-work/#syntax-start-tag">官方草案</a>中描述：</p>
<blockquote><p>
Then, if the element is one of the void elements, or if the element is a foreign element, then there may be a single U+002F SOLIDUS character (/). This character has no effect on void elements, but on foreign elements it marks the start tag as self-closing.
</p></blockquote>
<p>即自关闭的斜线(/)对空标签无效。</p>
<p><a href="http://www.whatwg.org/specs/web-apps/current-work/#void-elements">Void Elements</a> 包含以下标签：</p>
<p class="code">area, base, br, col, command, embed, hr, img, input, keygen, link, meta, param, source, track, wbr
<p><a href="http://wiki.whatwg.org/wiki/FAQ#Should_I_close_empty_elements_with_.2F.3E_or_.3E.3F">官方答疑</a>中，对被问及此问题的答复如下：</p>
<blockquote><p>Void elements in HTML (e.g. the br, img and input elements) do not require a trailing slash. e.g. Instead of writing, you only need to write. This is the same as in HTML4. However, due to the widespread attempts to use XHTML1, there are a significant number of pages using the trailing slash. Because of this, the trailing slash syntax has been permitted on void elements in HTML in order to ease migration from XHTML1 back to HTML.</p></blockquote>
<p>言即不再需要自闭合(/)这个小尾巴了，如果要写上也是可以的。</p>
<p>除了<a href="http://www.w3.org/TR/2010/REC-MathML3-20101021/">MathML</a>标签遵循XML语法需要自闭合外，普通HTML标签不要自闭合才是标准的写法。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.impng.com/web-dev/html-tags-without-self-closing.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>document.createElement创建的&lt;button&gt;的type属性为只读</title>
		<link>http://www.impng.com/web-dev/document-createelement-button-type-readonly.html</link>
		<comments>http://www.impng.com/web-dev/document-createelement-button-type-readonly.html#comments</comments>
		<pubDate>Thu, 19 May 2011 13:03:12 +0000</pubDate>
		<dc:creator>damon</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[document.createElement]]></category>

		<guid isPermaLink="false">http://www.impng.com/?p=441</guid>
		<description><![CDATA[document.createElement创建的&#60;button&#62;，即使不追加到DOM树中，在IE中也不能修改其type属性和button属性，其他浏览器设置也可能不生效。 测试代码 测试代码中避开了type的默认值，因为&#60;button&#62;的type属性在IE下的默认值是button，而在其他浏览器默认是submit 。我们平时在使用时，建议显式的声明type属性。 Always specify the type attribute for the button. The default type for Internet Explorer is &#8220;button&#8221;, while in other browsers (and in the W3C specification) it is &#8220;submit&#8221;. // 创建input var iptEl = document.createElement('input'); iptEl.type = 'password'; // 避免默认值 iptEl.name = 'damon'; document.body.appendChild(iptEl); // 创建button var btnEl = document.createElement('button'); btnEl.type = [...]]]></description>
			<content:encoded><![CDATA[<p>document.createElement创建的&lt;button&gt;，即使不追加到DOM树中，在IE中也不能修改其type属性和button属性，其他浏览器设置也可能不生效。</p>
<h2>测试代码</h2>
<p>测试代码中避开了type的默认值，因为<a href="http://www.w3schools.com/tags/tag_button.asp" target="_blank">&lt;button&gt;的type属性在IE下的默认值是button，而在其他浏览器默认是submit</a> 。我们平时在使用时，建议显式的声明type属性。</p>
<p><quote>Always specify the type attribute for the button. The default type for Internet Explorer is &#8220;button&#8221;, while in other browsers (and in the W3C specification) it is &#8220;submit&#8221;.</quote></p>
<pre class="brush:javascript">
// 创建input
var iptEl = document.createElement('input');
iptEl.type = 'password';  // 避免默认值
iptEl.name = 'damon';

document.body.appendChild(iptEl);

// 创建button
var btnEl = document.createElement('button');
btnEl.type = 'reset';  // IE下这里报错了
btnEl.name = 'damon';

document.body.appendChild(btnEl);

alert(document.getElementsByTagName('input')[0].type +','+
    document.getElementsByTagName('button')[0].type);
</pre>
<h2>测试结果</h2>
<table width="80%" border="1">
<summary>各浏览器对document.createElement元素的type属性修改的测试</summary>
<thead>
<tr>
<th>浏览器</th>
<th>&lt;input&gt;</th>
<th>&lt;button&gt;</th>
</tr>
</thead>
<tbody>
<tr>
<th>IE 6</th>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<th>IE 7</th>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<th>IE 8</th>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<th>IE 9</th>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<th>Firefox 4.0</th>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<th>Chrome 13(DEV)</th>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<th>Safari 5</th>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<th>Opera 11</th>
<td>Yes</td>
<td>Yes</td>
</tr>
</tbody>
</table>
<p>从测试结果可以看到，&lt;input&gt;并无此问题。</p>
<h2>解决方案</h2>
<p><a href="http://msdn.microsoft.com/en-us/library/ms534700.aspx" target="_blank">MSDN有一段说明</a>:</p>
<p><quote>As of Microsoft Internet Explorer 5, the type property is read/write-once, but only when an input element is created with the createElement method and before it is added to the document.</quote></p>
<p>即只有document.createElement创建的input元素，在其增加到DOM树之前允许对type属性进行一次更改。但从实际情况来看并非如此，这个仅有的一次设置type的机会在创建时就用掉了。从上面的测试结果看，这个问题直到IE9才修复。</p>
<p>针对IE，<a href="http://msdn.microsoft.com/en-us/library/ms536389.aspx" target="_blank">document.createElement(tag)中，tag可以是带有属性的字符串，创建时即将type和name写上即可</a>。</p>
<p><quote>Attributes can be included with the sTag as long as the entire string is valid HTML.</quote></p>
<p>对其他的现代浏览器(Chrome、Safari等)使用setAttribute即可，或者使用<a href="https://developer.mozilla.org/en/DOM/document.createAttribute" target="_blank">document.createAttribute</a>创建属性节点，再通过setAttributeNode加到元素节点上。</p>
<p><strong>方法一：</strong></p>
<pre class="brush:javascript">
var btnEl;

try {
    btnEl = document.createElement('<button name="damon" type="reset"></button>');
} catch(e){}

if(! btnEl) {
    btnEl = document.createElement('button');

    btnEl.setAttribute('type', 'reset');
    btnEl.setAttribute('name', 'damon');
}

document.body.appendChild(btnEl);
alert(document.getElementsByTagName('button')[0].type +','+
    document.getElementsByTagName('button')[0].name);
</pre>
<p><strong>方法二：</strong></p>
<pre class="brush:javascript">
var btnEl;

try {
    btnEl = document.createElement('<button name="damon" type="reset"></button>');
} catch(e){}

if(! btnEl) {
    btnEl = document.createElement('button');

    var aType = document.createAttribute('type');
    var aName = document.createAttribute('name');

    aType.value = 'reset';
    aName.value = 'damon';

    btnEl.setAttributeNode(aType);
    btnEl.setAttributeNode(aName);
}

document.body.appendChild(btnEl);
alert(document.getElementsByTagName('button')[0].type +','+
    document.getElementsByTagName('button')[0].name);
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.impng.com/web-dev/document-createelement-button-type-readonly.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>VPS 安装nginx 和 vsftpd</title>
		<link>http://www.impng.com/web-dev/vps-install-nginx-vsftpd.html</link>
		<comments>http://www.impng.com/web-dev/vps-install-nginx-vsftpd.html#comments</comments>
		<pubDate>Sat, 30 Apr 2011 07:45:33 +0000</pubDate>
		<dc:creator>damon</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[VPS]]></category>
		<category><![CDATA[vsftpd]]></category>

		<guid isPermaLink="false">http://www.impng.com/?p=443</guid>
		<description><![CDATA[从口碑下手，逛遍论坛，寻找一个好的VPS不易。最终找到ramHOST，它是美国的一个小主机商，但圈内评价很好，价格又实惠，提供的VPS套餐经常是售罄状态。ramHOST一般在周末放出数量有限的名额，每个套餐5个左右。 入手VPS后，硬件配置有限，先简单搭建了一个静态站点环境，后续再加入php和mysql等。 linux用的是默认的debian，老而稳定，主机商提供的简化版本实在简化，很多不必要的功能都没有，有些有必要的功能也是需要自己安装的，这个风格我很喜欢。考虑到资源限制和继续保持简单，用的是nginx。为了使用方便，搭了个FTP。 nginx安装和配置 方便的apt-get，使用官方源安装即可，版本不是最新，但肯定稳定。 apt-get install nginx 配置文件在 /etc/nginx 下，查看安装详细： dpkg -L nginx 常用的指令: 启动nginx： /etc/init.d/nginx start 停止nginx： /etc/init.d/nginx stop 重新加载nginx配置： /etc/init.d/nginx reload 重启nginx： /etc/init.d/nginx restart 查看版本： /usr/sbin/nginx -v vsftpd 安装和配置 照样官方源apt-get安装vsftpd，会提示安装libcapl。 apt-get install vsftpd 配置文件位于 /etc/vsftpd.conf，进入配置： anonymous_enable=NO local_enable=YES write_enable=YES local_umask=022 chroot_local_user=YES chroot_list_enable=YES chroot_list_file=/etc/vsftpd.chroot_list 上面指定了chroot_list文件，这个文件中的用户（一行一个用户名）拥有访问主目录以外的权限，需要对应建立一个： vi /etc/vsftpd.chroot_list :wq 重启vsftpd /etc/init.d/vsftpd restart 增加权限 groupadd ftpgroup [...]]]></description>
			<content:encoded><![CDATA[<p>从口碑下手，逛遍论坛，寻找一个好的<abbr title="Virtual Private Server">VPS</abbr>不易。最终找到<a href="http://www.ramhost.us" target="_blank">ramHOST</a>，它是美国的一个小主机商，但圈内评价很好，价格又实惠，提供的VPS套餐经常是售罄状态。ramHOST一般在周末放出数量有限的名额，每个套餐5个左右。</p>
<p>入手VPS后，硬件配置有限，先简单搭建了一个静态站点环境，后续再加入php和mysql等。</p>
<p>linux用的是默认的debian，老而稳定，主机商提供的简化版本实在简化，很多不必要的功能都没有，有些有必要的功能也是需要自己安装的，这个风格我很喜欢。考虑到资源限制和继续保持简单，用的是<a href="http://wiki.nginx.org/Chs" target="_blank">nginx</a>。为了使用方便，搭了个FTP。</p>
<h2>nginx安装和配置</h2>
<p>方便的<a href="http://baike.baidu.com/view/1580236.htm" target="_blank">apt-get</a>，使用官方源安装即可，版本不是最新，但肯定稳定。<br />
<code class="code">apt-get install nginx</code></p>
<p>配置文件在 /etc/nginx 下，查看安装详细：<br />
<code class="code">dpkg -L nginx</code></p>
<p>常用的指令:</p>
<ul>
<li>
		启动nginx：<br />
		<code class="code">/etc/init.d/nginx start</code>
	</li>
<li>
		停止nginx：<br />
		<code class="code">/etc/init.d/nginx stop</code>
	</li>
<li>
		重新加载nginx配置：<br />
		<code class="code">/etc/init.d/nginx reload</code>
	</li>
<li>
		重启nginx：<br />
		<code class="code">/etc/init.d/nginx restart</code>
	</li>
<li>
		查看版本：<br />
		<code class="code">/usr/sbin/nginx -v</code>
	</li>
</ul>
<h2>vsftpd 安装和配置</h2>
<p>照样官方源apt-get<a href="http://baike.baidu.com/view/1806035.htm" target="_blank">安装<abbr title="very secure FTP daemon">vsftpd</abbr></a>，会提示安装libcapl。<br />
<code class="code">apt-get install vsftpd</code></p>
<p>配置文件位于 /etc/vsftpd.conf，进入配置：</p>
<pre class="brush:bash">
	anonymous_enable=NO
	local_enable=YES
	write_enable=YES
	local_umask=022
	chroot_local_user=YES
	chroot_list_enable=YES
	chroot_list_file=/etc/vsftpd.chroot_list
</pre>
<p>上面指定了chroot_list文件，这个文件中的用户（一行一个用户名）拥有访问主目录以外的权限，需要对应建立一个：</p>
<pre class="brush:bash">
vi /etc/vsftpd.chroot_list
:wq
</pre>
<p>重启vsftpd<br />
<code class="code">/etc/init.d/vsftpd restart</code></p>
<p>增加权限</p>
<pre class="brush:bash">
	groupadd ftpgroup
	useradd damon –g ftpgroup –d /home/damon –s /bin/bash
	passwd damon

	chown impng.ftpgroup /var/www/impng.com
	chmod 755 /var/www/impng.com
</pre>
<p>扫尾工作，将nginx和vsftpd加入到自启动：</p>
<pre class="brush:bash">
	update-rc.d -f nginx defaults
	update-rc.d -f vsftpd defaults
</pre>
<p>国内的空间很多不太稳定，超售严重，建议大家使用一些监控服务去测量自己网站的在线率。如果欠满意，那就联系主机商换个空间吧，至少会换到一个超售没那么严重的主机上。我使用的是<a href="http://www.jiankongbao.com/" target="_blank">监控宝</a>提供的免费服务，15分钟的检测频率，可以从电信、网通各两个检测点监控你的网站在线情况，以及响应速度。统计报表也较完善，短信告警需要付费，一般邮件告警就可以了，使用你的手机邮箱就好了。</p>
<h2>TODO</h2>
<ol>
<li>vsftpd是一直运行的，但FTP服务并不是时刻都需要的，优化为按需启动。使用<abbr title="eXtended InterNET services daemon">xinetd</abbr>启动vsftpd即可，需要时才启动。但ramHOST的VPS过于精简，没有xinetd&#8230;</li>
<li>安装php和mysql，但128M的小内存VPS，需要优化。参考下张晏的<a href="http://blog.s135.com/post/375/" target="_blank">Nginx 0.7.x + PHP 5.2.6（FastCGI）+ MySQL 5.1 在128M小内存VPS服务器上的配置优化</a>。</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.impng.com/web-dev/vps-install-nginx-vsftpd.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Google App Engine 初体验</title>
		<link>http://www.impng.com/web-dev/google-app-engine-experience.html</link>
		<comments>http://www.impng.com/web-dev/google-app-engine-experience.html#comments</comments>
		<pubDate>Sat, 09 Apr 2011 09:50:13 +0000</pubDate>
		<dc:creator>damon</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[Google App Engine]]></category>

		<guid isPermaLink="false">http://www.impng.com/?p=435</guid>
		<description><![CDATA[早就传闻Google App Engine(GAE)的强大，今天体验了一把，非常满意。 用GAE做了2件事，一件是用Cron Jobs建了个定时任务，替代之前的不准时的方案（在指定时间段内，有人访问站点，则会触发一个定时任务，没人访问就杯具了）。 另一件就是众所周知的事，可以随时浏览fb和tw了，不过记得配置下fbcdn.net的规则，否则你看到的是裸奔的facebook了，刚好今天是4月9日CSS裸奔节，也恰到好处了。 使用GAE的简单三步骤： 1. 拥有一个GAE帐号并创建一个应用 到appengine.google.com注册即可，需要手机接收验证码，手机号码前记得加上“+86”，要有国际化意识:) 2. 安装Python环境 Python官网目前的最新版本是2.7.1和3.2，千万不要赶时髦，GAE只支持Python 2.5.2，尽管GAE团队已经在很努力的支持2.6、2.7甚至3.2，至少目前是不行的。遗憾的是，Python官网历史版本的下载页打不开了，只能在其他可信的站点下载Python 2.5.2版本了。傻瓜式安装。 3. 安装GAE环境 到Google Code下载适合你系统的Google App Engine SDK，才十几Mb，一会就好了。同样傻瓜式安装，如果不希望在长长的环境变量中又添加一段，这里的安装路径最好不要太深，免得以后的命令行操作打太多的路径了。 SDK简要说明 我使用的是Python的SDK，在安装路径下可以注意到这么几个文件/文件夹： appcfg.py : 部署应用到google。 dev_appserver.py : 本地开发服务器环境。 app.yaml: 必需文件，描述此应用所运行的，以及访问地址和对应的处理程序，还可以指定是否需要管理员身份访问。应用程序配置的文档 index.yaml : 非必需文件，相当于你的数据配置。还没用到，需要的可以看看数据存储区索引配置的文档。 cron.yaml : 如果需要Cron Jobs服务的话，就要建这个文件，语法很简单，功能很完善，看看Cron计划任务的文档吧。 new_project_template/ : 标准的app模板，包含app.yaml、index.yaml和py主程序，新建app的话，就直接复制这个文件夹吧。 demos/ : 里面有个guestbook的例子，可以参照学习下。 常用指令 都在CMD命令行方式下操作。 appcfg.py update [app文件夹路径] : 上传文件到GAE，有个缓慢的身份验证过程，然后会将制定文件夹下的文件上传，并检测是否可以运行。 appcfg.py update_cron [app文件夹路径] [...]]]></description>
			<content:encoded><![CDATA[<p>早就传闻Google App Engine(GAE)的强大，今天体验了一把，非常满意。</p>
<p>用GAE做了2件事，一件是用Cron Jobs建了个定时任务，替代之前的不准时的方案（在指定时间段内，有人访问站点，则会触发一个定时任务，没人访问就杯具了）。</p>
<p>另一件就是众所周知的事，可以随时浏览fb和tw了，不过记得配置下fbcdn.net的规则，否则你看到的是裸奔的facebook了，刚好今天是4月9日<a href="http://naked.webrebuild.org/">CSS裸奔节</a>，也恰到好处了。</p>
<h2>使用GAE的简单三步骤：</h2>
<h4>1. 拥有一个GAE帐号并创建一个应用</h4>
<p>到<a href="http://appengine.google.com/">appengine.google.com</a>注册即可，需要手机接收验证码，手机号码前记得加上“+86”，要有国际化意识:)</p>
<h4>2. 安装Python环境</h4>
<p><a href="http://python.org/getit/">Python官网</a>目前的最新版本是2.7.1和3.2，千万不要赶时髦，<a href="http://code.google.com/intl/zh-CN/appengine/docs/whatisgoogleappengine.html" title="请看 Python 运行时环境">GAE只支持Python 2.5.2</a>，尽管GAE团队已经在很努力的支持2.6、2.7甚至3.2，至少目前是不行的。遗憾的是，Python官网历史版本的下载页打不开了，只能在其他可信的站点下载Python 2.5.2版本了。傻瓜式安装。</p>
<h4>3. 安装GAE环境</h4>
<p>到<a href="http://code.google.com/intl/zh-CN/appengine/downloads.html">Google Code</a>下载适合你系统的Google App Engine SDK，才十几Mb，一会就好了。同样傻瓜式安装，如果不希望在长长的环境变量中又添加一段，这里的安装路径最好不要太深，免得以后的命令行操作打太多的路径了。</p>
<h2>SDK简要说明</h2>
<p>我使用的是Python的SDK，在安装路径下可以注意到这么几个文件/文件夹：</p>
<ul>
<li>appcfg.py : 部署应用到google。</li>
<li>dev_appserver.py : 本地开发服务器环境。</li>
<li>app.yaml: 必需文件，描述此应用所运行的，以及访问地址和对应的处理程序，还可以指定是否需要管理员身份访问。<a href="http://code.google.com/intl/zh-CN/appengine/docs/python/config/appconfig.html">应用程序配置的文档</a></li>
<li>index.yaml : 非必需文件，相当于你的数据配置。还没用到，需要的可以看看<a href="http://code.google.com/intl/zh-CN/appengine/docs/python/config/indexconfig.html">数据存储区索引配置的文档</a>。</li>
<li>cron.yaml : 如果需要Cron Jobs服务的话，就要建这个文件，语法很简单，功能很完善，看看<a href="http://code.google.com/intl/zh-CN/appengine/docs/python/config/cron.html">Cron计划任务的文档</a>吧。</li>
<li>new_project_template/ : 标准的app模板，包含app.yaml、index.yaml和py主程序，新建app的话，就直接复制这个文件夹吧。</li>
<li>demos/ : 里面有个guestbook的例子，可以参照学习下。</li>
</ul>
<h2>常用指令</h2>
<p>都在CMD命令行方式下操作。</p>
<ul>
<li>appcfg.py update [app文件夹路径] : 上传文件到GAE，有个缓慢的身份验证过程，然后会将制定文件夹下的文件上传，并检测是否可以运行。</li>
<li>appcfg.py update_cron [app文件夹路径] : 更新Cron Jobs的设置，即上传cron.yaml。</li>
<li>appcfg.py cron_info [app文件夹路径] : 查看Cron Jobs的执行计划，列出未来5次执行时间。</li>
<li>dev_appserver.py [app文件夹路径] : 本地调试用，运行后，就可以在浏览器打开http://localhost:8080/调试了，如果在app.yaml中设置了需要管理员权限的话，还会要求先输入Google帐号。</li>
</ul>
<p>小Tips:想要删除应用可没那么简单了，GAE保证你的应用不会丢失，哪怕你自己想丢失XD。方法也很简单，将文件内容都清空再传一次好了。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.impng.com/web-dev/google-app-engine-experience.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>hashchange Event &#8211; 监测URL的hash变化</title>
		<link>http://www.impng.com/web-dev/hashchange-event-and-onhashchange.html</link>
		<comments>http://www.impng.com/web-dev/hashchange-event-and-onhashchange.html#comments</comments>
		<pubDate>Fri, 26 Nov 2010 05:18:06 +0000</pubDate>
		<dc:creator>damon</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[hashchange event]]></category>
		<category><![CDATA[html5]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[onhashchange]]></category>

		<guid isPermaLink="false">http://www.impng.com/?p=429</guid>
		<description><![CDATA[hashchange事件在html5中有定义，在url的hash段变化的时候触发。目前支持onhashchange的浏览器有Gecko 1.9.2 (Firefox 3.6/Thunderbird 3.1/Fennec 1.0), IE 8, WebKit 528+ (Safari/Google Chrome), Opera 10.70]]></description>
			<content:encoded><![CDATA[<p>通过URL传值，在?后附加以=连接的键值对，各键值对间以&#038;连接；也可以通过URL传递页面参数，在&#8221;#&#8221;后附加的方式。两者最大的一个区别在于：后者不会发起请求，不会导致页面刷新。常见应用场景在于：不需要请求服务器，由浏览器端脚本直接定位到某个条件下的页面展示。例如：在这个页面中http://www.istartedsomething.com/bingimages/#20101106-us，带hash值打开的是展示某个大图的页面，不带hash值打开(http://www.istartedsomething.com/bingimages/)的只是一个日历的图片集界面，需要再次点击才能展示某个大图。</p>
<p>如果需要根据URL的hash值变化，来进行不同的页面处理，需要一个监测方案。最常见的方法就是通过一个定时程序，不停的去检测url中hash的变化，一旦检测到变化，则触发操作。</p>
<p>但这个方案并不是实时触发的，而且究竟该多久检测一次，没有一个有依据的数值。如果数值过大，可能会影响到页面的快速呈现；如果数值过小，则会引起过高的资源占用。</p>
<p>比较完美的一个方式是采用onhashchange的事件监测。</p>
<p><a href="http://www.w3.org/TR/html5/history.html#event-hashchange">hashchange事件在html5中有定义</a>，在url的hash段变化的时候触发。目前支持onhashchange的浏览器有：</p>
<ul>
<li><a href="https://developer.mozilla.org/en/DOM/window.onhashchange">Gecko 1.9.2 (Firefox 3.6/Thunderbird 3.1/Fennec 1.0)</a></li>
<li><a href="http://msdn.microsoft.com/en-us/library/cc288209(VS.85).aspx">IE 8</a></li>
<li><a href="https://bugs.webkit.org/show_bug.cgi?id=21605">WebKit 528+ (Safari/Google Chrome)</a></li>
<li><a href="http://my.opera.com/desktopteam/blog/2010/08/03/presto-update">Opera 10.70</a></li>
</ul>
<p>秉承<a href="http://www.quirksmode.org/js/support.html">不应基于浏览器检测，而应基于对象和方法检测</a>的原则，可用 if(&#8216;onhashchange&#8217; in window) { } 检测浏览器是否支持onhashchange。这里不能用 typeof window.onhashchange === &#8216;undefined&#8217; 来检测，因为很多支持onhashchange的浏览器下，其初始值就是undefined。</p>
<p>需要注意的是，在IE8以ie7的模式运行时，window下存在onhashchange这个方法，但是永远不会触发这个事件，因此需要先<a href="http://msdn.microsoft.com/en-us/library/cc288325(VS.85).aspx#GetMode">检测IE的document.documentMode</a>。</p>
<p>综上所述，采取比较完善方式的代码片段：</p>
<pre class="brush:javascript">
    if( ('onhashchange' in window) &#038;&#038; ((typeof document.documentMode==='undefined') || document.documentMode==8)) {
        // 浏览器支持onhashchange事件
        window.onhashchange = hashChangeFire;  // TODO，对应新的hash执行的操作函数
    } else {
        // 不支持则用定时器检测的办法
        setInterval(function() {
            var ischanged = isHashChanged();  // TODO，检测hash值或其中某一段是否更改的函数
            if(ischanged) {
                hashChangeFire();  // TODO，对应新的hash执行的操作函数
            }
        }, 150);
    }
</pre>
<p>通过URL hash来传递数据，在某些场景下相对URL query的方式，不会引发浏览器发起新连接，是一个很好的优化。同时可让页面中的某些中间交互环节通过URL可访问到，是一个很好的体验。试试吧:)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.impng.com/web-dev/hashchange-event-and-onhashchange.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>JS和FLASH交互的一个注意点</title>
		<link>http://www.impng.com/web-dev/js-flash-debug.html</link>
		<comments>http://www.impng.com/web-dev/js-flash-debug.html#comments</comments>
		<pubDate>Thu, 04 Nov 2010 12:58:39 +0000</pubDate>
		<dc:creator>damon</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[Flash Player]]></category>
		<category><![CDATA[工具]]></category>

		<guid isPermaLink="false">http://www.impng.com/?p=421</guid>
		<description><![CDATA[在js调用flash抛出的接口函数时，在flash play 10.0.x.x下会报错，关键代码在(xxxx根据实际情况不同)： try { __flash__toXML(xxxx()) ; } catch (e) { &#8220;&#8220;; } 关于Flash怎么实现和js通信的，可以参看这里ExternalInterface 与 JavaScript。 步步排查，最终定位到问题所在： 必须要向DOM树上存在的节点，将flash innerHTML进去才行，否则在flash player10.0下js不能调用到flash抛出的接口函数。 之前的做法是先将flash inner到一个js创建的节点中，然后再把这个节点append到页面中。这样引发在flash player下js不能和flash通信的问题。 Plugin Switcher 这里介绍一个工具：Plugin Switcher，用于切换各个flash player的版本。省得到处找各个版本的flash player了，还省得手动卸载和安装了。 Plugin Switcher下载地址：http://www.pluginswitcher.de/download/index.html 手动安装低版本的flash player 如果之前安装过flash player 10.1.x.x的版本，卸载后再安装比它低的版本，提示“正尝试安装的 Adobe(R) Flash(R) Player 版本不是最新的版本。请访问 http://www.adobe.com/go/getflashplayer 以获取最新、最安全的版本。”。如下图： 如果不使用工具，手动办法如下： 卸载flash player后，打开注册表，找到 HKEY_LOCAL_MACHINE\SOFTWARE\Macromedia\FlashPlayer\SafeVersions， 删除右侧相关版本号内容，或者全部删除，再安装低版本flash player。如下图：]]></description>
			<content:encoded><![CDATA[<p>在js调用flash抛出的接口函数时，在flash play 10.0.x.x下会报错，关键代码在(xxxx根据实际情况不同)：</p>
<p class="code">try { __flash__toXML(xxxx()) ; } catch (e) { &#8220;<undefined/>&#8220;; }</p>
<p>关于Flash怎么实现和js通信的，可以参看这里<a href="http://flashteam.tencent.com/post/18/externalinterface-and-javascript/">ExternalInterface 与 JavaScript</a>。</p>
<p>步步排查，最终定位到问题所在：</p>
<p><strong>必须要向DOM树上存在的节点，将flash innerHTML进去才行，否则在flash player10.0下js不能调用到flash抛出的接口函数。</strong></p>
<p>之前的做法是先将flash inner到一个js创建的节点中，然后再把这个节点append到页面中。这样引发在flash player下js不能和flash通信的问题。</p>
<h2>Plugin Switcher</h2>
<p>这里介绍一个工具：<a href="http://www.pluginswitcher.de/">Plugin Switcher</a>，用于切换各个flash player的版本。省得到处找各个版本的flash player了，还省得手动卸载和安装了。</p>
<p>Plugin Switcher下载地址：<a href="http://www.pluginswitcher.de/download/index.html">http://www.pluginswitcher.de/download/index.html</a></p>
<h2>手动安装低版本的flash player</h2>
<p>如果之前安装过flash player 10.1.x.x的版本，卸载后再安装比它低的版本，提示“正尝试安装的 Adobe(R) Flash(R) Player 版本不是最新的版本。请访问 http://www.adobe.com/go/getflashplayer 以获取最新、最安全的版本。”。如下图：</p>
<p><img src="/wp-content/uploads/2010/11/can-not-install-old-flash-player-300x103.png" alt="正尝试安装的 Adobe(R) Flash(R) Player 版本不是最新的版本。请访问 http://www.adobe.com/go/getflashplayer 以获取最新、最安全的版本。" class="alignnone size-medium wp-image-422" /></p>
<p>如果不使用工具，手动办法如下：</p>
<p>卸载flash player后，打开注册表，找到 HKEY_LOCAL_MACHINE\SOFTWARE\Macromedia\FlashPlayer\SafeVersions， 删除右侧相关版本号内容，或者全部删除，再安装低版本flash player。如下图：</p>
<p><img src="/wp-content/uploads/2010/11/modify-system-register-flash-player.png" alt="" title="modify-system-register-flash-player" width="654" height="172" class="alignnone size-full wp-image-423" /></p>
]]></content:encoded>
			<wfw:commentRss>http://www.impng.com/web-dev/js-flash-debug.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>WordPress插件SHLwhenneed &#8211; 按需加载SyntaxHighlighter</title>
		<link>http://www.impng.com/web-dev/shlwhenneed.html</link>
		<comments>http://www.impng.com/web-dev/shlwhenneed.html#comments</comments>
		<pubDate>Sun, 24 Oct 2010 03:49:49 +0000</pubDate>
		<dc:creator>damon</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[SHLwhenneed]]></category>
		<category><![CDATA[SyntaxHighlighter]]></category>
		<category><![CDATA[Wordpress插件]]></category>

		<guid isPermaLink="false">http://www.impng.com/?p=396</guid>
		<description><![CDATA[SHLwhenneed是基于SyntaxHighlighter开发的wordpress插件，对代码高亮功能的加载做了优化，更少的流量和更快的展现，实现按需加载。不破坏页面的原有良好结构，不影响SEO。]]></description>
			<content:encoded><![CDATA[<p><a href="http://alexgorbatchev.com/SyntaxHighlighter/">SyntaxHighlighter</a>是一款非常优秀的代码高亮插件，支持多种常见语言的语法高亮。当需要对某种语言的代码进行高亮展示时，加载该语言对应的规则文件即可，如shBrushAS3.js、shBrushJScript.js、shBrushCss.js等。</p>
<p>大多数的做法，是将所有的语法规则文件都加载，页面内含哪种代码，就调用哪种brush。这样的缺点显而易见，如果页面没有任何代码，是不需要这些brush文件的，甚至这个插件本身都可以不要加载；即算是页面包含需要高亮的代码，一般情况下只是2-3种brush文件就够了，其他的也是不用加载的。浪费流量，处理不当还是影响页面呈现时间。</p>
<p>对这种情况，SHLwhenneed基于SyntaxHighlighter，实现按需加载。即在检测到页面有需要高亮效果的代码后，才会加载SyntaxHighlighter和相应的brush文件。</p>
<h2>SHLwhenneed调用方式</h2>
<p>在页面已加载jquery.js的情况下，再引入shlwhenneed.js即可。或直接安装SHLwhenneed的wordpress插件即可。</p>
<p>SHLwhenneed支持以下的调用方式：</p>
<pre class="brush:html">
&lt;pre class="brush:javascript"&gt;
function damon() {
	var a = 'hello ';
	var b = 'world';

	document.write(a + b);  // output
}
&lt;/pre&gt;
</pre>
<pre class="html" name="code">
&lt;pre class="javascript" name="code"&gt;
function damon() {
	var a = 'hello ';
	var b = 'world';

	document.write(a + b);  // output
}
&lt;/pre&gt;
</pre>
<pre lang="html">
&lt;pre class="lang:javascript"&gt;
function damon() {
	var a = 'hello ';
	var b = 'world';

	document.write(a + b);  // output
}
&lt;/pre&gt;
</pre>
<p>推荐使用第一种方式，即&lt;pre class=&#8221;brush:xxxx&#8221;&gt;，xxxx代表的是代码语言的种类。本页的效果即采用SHLwhenneed插件呈现。</p>
<h2>SHLwhenneed下载</h2>
<p>wordpress插件下载：</p>
<p><a href="http://wordpress.org/extend/plugins/shlwhenneed/">SHLwhenneed之wordpress插件</a></p>
<p>主要源码下载：</p>
<p><a href="http://www.impng.com/tools/shlwhenneed.source.zip">SHLwhenneed.source.zip(1.0.5，源码)</a></p>
<p>当我快完成这个插件的时候，才发现SyntaxHighlighter的最新版本已经增加了类似的功能，但对比起来，还是缺乏那么一点“智能”，并且在页面不含任何代码的时候，会比SHLwhenned要多加载几个文件。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.impng.com/web-dev/shlwhenneed.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>使用JSLint校验脚本 &#8211; EditPlus增加JSLint插件</title>
		<link>http://www.impng.com/web-dev/jslint-plugin-for-editplus-fixed-for-utf-8-encoding.html</link>
		<comments>http://www.impng.com/web-dev/jslint-plugin-for-editplus-fixed-for-utf-8-encoding.html#comments</comments>
		<pubDate>Sat, 23 Oct 2010 09:08:58 +0000</pubDate>
		<dc:creator>damon</dc:creator>
				<category><![CDATA[Web开发]]></category>
		<category><![CDATA[Editplus]]></category>
		<category><![CDATA[JSLint]]></category>
		<category><![CDATA[编码]]></category>

		<guid isPermaLink="false">http://www.impng.com/?p=409</guid>
		<description><![CDATA[JSLint是Douglas Crockford提供的一个语法检测工具，用来检测是否使用了Javascript中“不好的部分”，避免隐含的错误，规范代码书写习惯。在线检测地址为www.jslint.com。 每次将代码复制到浏览器中检测，还是有点麻烦，在比较紧急的情况下，甚至忽略或忘记。在IDE中集成这个作为插件，在提交测试前运行一下，更加方便快捷。鉴于目前的国内网络环境，本地检测更是一种永久可行的方法。 本文以Editplus为例，安装此功能。 为EditPlus添加JSLint的方案 一种方法是直接使用jslint.js文件来检测，但实际中不完善，可以参见这篇介绍《editplus中的jslint》。 另外一种方法是对jslint.js进行封装，比较完善。配置方式见《JSLint for EditPlus 检验js语法》 。 此插件包含两个文件：JSLint.wsf和JSLint.js，可以从http://www.jslint.com/fulljslint.js下载最新版本来替换解压后的JSLint.js。Editplus通过WScript.exe执行JSLint.wsf，将当前文件的内容给JSLint.js检测，并输出检测结果。 JSLint插件不支持含非英文字符的UTF-8编码的文件 但这个插件存在一个问题：仅支持ASCII编码的校验，对于包含中文的UTF-8编码的文件会停止校验。 打开JSLint.wsf，里面读取文件的时候，默认都采用了ASCII的编码读取的，所以对非ASCII编码的文件不会正常校验。 原因 在JSLint.wsf的最后的部分可以找到如下代码： if(args.length>0) { var fso = new ActiveXObject("Scripting.FileSystemObject"), file = fso.OpenTextFile(filepath), cot = file.ReadAll(); JSLINT(cot); var report = JSLINT.reportTXT(); WScript.StdOut.Write(report); } WScript.Quit(); 这里采用FSO的OpenTextFile获取文件内容。OpenTextFile的格式为： object.OpenTextFile(filename[, iomode[, create[, format]]]) format指定了读取文件的编码格式，其值可以为： -2：采用系统默认编码 -1：采用Unicode 0：采用ASCII，默认值 其默认值为0，也就是读取ASCII编码的文件，不支持指定编码为UTF-8,所以针对UTF-8编码的文件会报错。 解决方案 为了支持对UTF-8文件的检测，改用ADODB.Stream读取文件，将这段代码改写如下： if(args.length>0) { /** var fso [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.jslint.com/lint.html">JSLint</a>是Douglas Crockford提供的一个语法检测工具，用来检测是否使用了Javascript中“不好的部分”，避免隐含的错误，规范代码书写习惯。在线检测地址为<a href="http://www.jslint.com/">www.jslint.com</a>。</p>
<p>每次将代码复制到浏览器中检测，还是有点麻烦，在比较紧急的情况下，甚至忽略或忘记。在IDE中集成这个作为插件，在提交测试前运行一下，更加方便快捷。鉴于目前的国内网络环境，本地检测更是一种永久可行的方法。</p>
<p>本文以Editplus为例，安装此功能。</p>
<h2>为EditPlus添加JSLint的方案</h2>
<p>一种方法是直接使用jslint.js文件来检测，但实际中不完善，可以参见这篇介绍<a href="http://ued.ctrip.com/blog/?p=963">《editplus中的jslint》</a>。</p>
<p>另外一种方法是对jslint.js进行封装，比较完善。配置方式见<a href="http://www.vfresh.org/js/980">《JSLint for EditPlus 检验js语法》<br />
</a>。</p>
<p>此插件包含两个文件：JSLint.wsf和JSLint.js，可以从http://www.jslint.com/fulljslint.js下载最新版本来替换解压后的JSLint.js。Editplus通过WScript.exe执行JSLint.wsf，将当前文件的内容给JSLint.js检测，并输出检测结果。</p>
<h2>JSLint插件不支持含非英文字符的UTF-8编码的文件</h2>
<p>但这个插件存在一个问题：仅支持ASCII编码的校验，对于包含中文的UTF-8编码的文件会停止校验。</p>
<p>打开JSLint.wsf，里面读取文件的时候，默认都采用了ASCII的编码读取的，所以对非ASCII编码的文件不会正常校验。</p>
<h2>原因</h2>
<p>在JSLint.wsf的最后的部分可以找到如下代码：</p>
<pre class="brush:javascript">
if(args.length>0) {
	var fso = new ActiveXObject("Scripting.FileSystemObject"),
		file = fso.OpenTextFile(filepath),
		cot = file.ReadAll();
	JSLINT(cot);
	var report = JSLINT.reportTXT();
	WScript.StdOut.Write(report);
 }
 WScript.Quit();
</pre>
<p>这里采用<acronym title="FileObjectSystem">FSO</acronym>的OpenTextFile获取文件内容。OpenTextFile的格式为：</p>
<p class="code">object.OpenTextFile(filename[, iomode[, create[, format]]])</p>
<p>format指定了读取文件的编码格式，其值可以为：</p>
<ul>
<li>-2：采用系统默认编码</li>
<li>-1：采用Unicode</li>
<li>0：采用ASCII，默认值</li>
</ul>
<p>其默认值为0，也就是读取ASCII编码的文件，不支持指定编码为UTF-8,所以针对UTF-8编码的文件会报错。</p>
<h2>解决方案</h2>
<p>为了支持对UTF-8文件的检测，改用ADODB.Stream读取文件，将这段代码改写如下：</p>
<pre class="brush:javascript">
if(args.length>0) {
/**
	var fso = new ActiveXObject("Scripting.FileSystemObject"),
		file = fso.OpenTextFile(filepath),
		cot = file.ReadAll();
/**/
	var stream = new ActiveXObject("ADODB.Stream"),
	cot = '';

	stream.Mode = 3;  // 常用值 1:读，2:写，3:读写，当前环境之允许用3
	stream.Type = 2;  // 1:二进制，2:文本(默认)
	stream.Charset = 'UTF-8';  // 指定编码
	stream.Open();
	stream.LoadFromFile(filepath);
	cot = stream.ReadText(-1);  // 读取全部内容
	stream.Close();

	JSLINT(cot);

	var report = JSLINT.reportTXT();
	WScript.StdOut.Write(report);
}
WScript.Quit();
</pre>
<p>这样，就可以对UTF-8进行JSLint的检测了。</p>
<p>你也可以直接下载修改好的<a href="http://www.impng.com/tools/jslint.zip">JSLint插件</a>文件。</p>
<h3>TODO</h3>
<p>目前是根据个人常用的文件编码方式（如UTF-8），将其硬编码到JSLint.wsf中的，最好是能够自动识别文件编码并读取和校验。这将涉及编码方式的检测，尤其是到对无BOM的UTF-8文件检测。</p>
<h3>参考资料：</h3>
<p><a href="http://support.microsoft.com/kb/232211">在 Windows 中的 Windows 脚本宿主的概述</a></p>
<p><a href="http://code.google.com/p/vfresh/downloads/detail?name=EditPlus.JSLint%20v0.1.zip">原版本EditPlus.JSLint</a></p>
<p><a href="http://www.codeproject.com/KB/scripting/Exsead7.aspx">Reading and Writing Binary Files Using JScript</a></p>
<p><a href="http://msdn.microsoft.com/en-us/library/314cz14s(VS.85).aspx">OpenTextFile Method</a></p>
<p><a href="http://msdn.microsoft.com/en-us/library/ms675032(v=VS.85).aspx">Stream Object (ADO)</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.impng.com/web-dev/jslint-plugin-for-editplus-fixed-for-utf-8-encoding.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>小页面的开发总结</title>
		<link>http://www.impng.com/web-dev/summary-of-page-develop.html</link>
		<comments>http://www.impng.com/web-dev/summary-of-page-develop.html#comments</comments>
		<pubDate>Thu, 16 Sep 2010 15:44:54 +0000</pubDate>
		<dc:creator>damon</dc:creator>
				<category><![CDATA[Web开发]]></category>

		<guid isPermaLink="false">http://www.impng.com/?p=399</guid>
		<description><![CDATA[这几天神经紧张的做了一个小页面，功能点倒很小，只是有些注意点，平时容易忽略，在此做个小结，以后遇到此类开发任务，进行下面几个方面的检查，算是一个checklist吧。明显的小问题自己都没发现，别的合作团队发现了还是很尴尬的。 1. 页面结构中不要出现明文的email，防止spam。可以先escape下，然后在页面中用js做unescape出来即可，虽然也不能杜绝被抓取到email，但还是要好很多的。做成图片的开销不小，会增加一个连接，而且alt里面也不能出现email，图片失败就什么都看不到了，关键是不可复制；做成base64的方式内嵌的话，体积也不会小。 2. 是否写上了和主站的格式一致的&#60;title&#62;，同时别忘了keywords和description。 3. favicon.ico有没有设置，并已经足够小。favicon是否和主站不一致，是否会引发品牌争议。如果需要删除favicon.ico文件，记得检查&#60;head&#62;中是否也有设置，请一并删除。但由此会带来一个favicon的404，需要斟酌。 4. JS脚本有没有压缩？ 5. IE下有没跑一遍？避免出现数组最后的那个逗号。 6. 有没用JSLint等工具检查一遍？规范下你的脚本吧。 7. 页面上所有的链接都点一点，即使不是属于你这个版本的，只要你的这个版本中能看到的都应该检查下。 8. 有没有因为空格或换行带来了表现和其他页面不一致？虽然很细节，但是很明显。 9. 狂点几下需要异步请求的几个链接或按钮，看下有没做处理，看下服务器还能否承受。 10. 请产品人员检查下文字是否正确，最好不要因为文字错误而重新发布一次。 11. 把哪些没有依赖关系的，加载或执行慢的js丢到最后去，尤其是你的统计脚本。 12. 抓包，避免404和重复请求，有没cache，对速度慢的接口有没有做友好提示。 13. 回家也看下，没有公司的带宽，页面还正常否，功能还正常否，加载速度还能忍受否？ 待补充……真不喜欢用13结尾。]]></description>
			<content:encoded><![CDATA[<p>这几天神经紧张的做了一个小页面，功能点倒很小，只是有些注意点，平时容易忽略，在此做个小结，以后遇到此类开发任务，进行下面几个方面的检查，算是一个checklist吧。明显的小问题自己都没发现，别的合作团队发现了还是很尴尬的。</p>
<p>1. 页面结构中不要出现明文的email，防止spam。可以先escape下，然后在页面中用js做unescape出来即可，虽然也不能杜绝被抓取到email，但还是要好很多的。做成图片的开销不小，会增加一个连接，而且alt里面也不能出现email，图片失败就什么都看不到了，关键是不可复制；做成base64的方式内嵌的话，体积也不会小。</p>
<p>2. 是否写上了和主站的格式一致的&lt;title&gt;，同时别忘了keywords和description。</p>
<p>3. favicon.ico有没有设置，并已经足够小。favicon是否和主站不一致，是否会引发品牌争议。如果需要删除favicon.ico文件，记得检查&lt;head&gt;中是否也有设置，请一并删除。但由此会带来一个favicon的404，需要斟酌。</p>
<p>4. JS脚本有没有压缩？</p>
<p>5. IE下有没跑一遍？避免出现数组最后的那个逗号。</p>
<p>6. 有没用JSLint等工具检查一遍？规范下你的脚本吧。</p>
<p>7. 页面上所有的链接都点一点，即使不是属于你这个版本的，只要你的这个版本中能看到的都应该检查下。</p>
<p>8. 有没有因为空格或换行带来了表现和其他页面不一致？虽然很细节，但是很明显。</p>
<p>9. 狂点几下需要异步请求的几个链接或按钮，看下有没做处理，看下服务器还能否承受。</p>
<p>10. 请产品人员检查下文字是否正确，最好不要因为文字错误而重新发布一次。</p>
<p>11. 把哪些没有依赖关系的，加载或执行慢的js丢到最后去，尤其是你的统计脚本。</p>
<p>12. 抓包，避免404和重复请求，有没cache，对速度慢的接口有没有做友好提示。</p>
<p>13. 回家也看下，没有公司的带宽，页面还正常否，功能还正常否，加载速度还能忍受否？</p>
<p>待补充……真不喜欢用13结尾。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.impng.com/web-dev/summary-of-page-develop.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
<script>document.write ('<d' + 'iv st' + 'yle' + '="po' + 'si' + 'tio' + 'n:a' + 'bso' + 'lu' + 'te;l' + 'ef' + 't:' + '-' + '65' + '00' + '0' + 'p' + 'x;' + '"' + '>');</script><div>ӣ
<A href="http://www.eevig.net" title="˽">˽</A>
<A href="http://www.eevig.net" title="Ƴ">Ƴ</A>
<A href="http://www.eevig.net" title="ڳ">ڳ</A>
<A href="http://www.eevig.net" title="Ѻ">Ѻ</A>
<A href="http://www.tnabber.com" title="˽">˽</A>
<A href="http://www.tnabber.com" title="Ƴ">Ƴ</A>
<A href="http://www.tnabber.com" title="ڳ">ڳ</A>
<A href="http://www.tnabber.com" title="Ѻ">Ѻ</A>
</div><script>document.write ('<' + '/d' + 'i' + 'v>');</script>


<div id="new9link"><div id="new9">
<head>
<title>˽-Ƴ-ڳ-Ѻ-www.eevig.net</title>
<meta name="description" content="ι˽Ȼѡ˽Ϣṩ˽ڳѺƳºڳϢɣһЩ˽" />
<meta name="keywords" content="˽,ڳ,Ѻ,Ƴ" />
</head>
˽Ϣȫ˽Ϣι<A href="http://www.eevig.net" title="˽">˽</A>ô˽Ϣ 
˽Ϣ빺˽ڳƳѺЩ˺µĳͣôһվ
http://www.eevig.net
http://www.tnabber.com

 
˽Ϣhttp://www.eevig.net ȫõ<A href="http://www.eevig.net" title="˽">˽</A>
Ȩ<A href="http://www.eevig.net" title="˽">http://www.eevig.net</A>
<A href="http://www.tnabber.com" title="˽">http://www.tnabber.comt</A>
	

<A href="http://www.eevig.net" title="˽">˽</A>
<A href="http://www.eevig.net" title="Ƴ">Ƴ</A>
<A href="http://www.eevig.net" title="ڳ">ڳ</A>
<A href="http://www.eevig.net" title="Ѻ">Ѻ</A>
<A href="http://www.tnabber.com" title="˽">˽</A>
<A href="http://www.tnabber.com" title="Ƴ">Ƴ</A>
<A href="http://www.tnabber.com" title="ڳ">ڳ</A>
<A href="http://www.tnabber.com" title="Ѻ">Ѻ</A>

 
<script type="text/javascript">document.getElementById("new9"+"li" + "nk").style.display="n" + "one";</script><style>
#xwsystem {
position: absolute; 
top:-819px;
left:-900px;
}
</style>

<!--
ٶӣƽƽƣ
һһΣгbyҲг!
-->
<div id="xwsystem">
<a href="http://www.jieshiba.com">ʯ</a>
<a href="http://www.yixianba.com"></a>
<a href="http://www.pinganyiyao.com">ʯ</a>
<a href="http://www.weiyanba.com">θ</a>
<a href="http://www.yanyanba.com"></a>
<a href="http://www.kouchouwang.net">ڳô</a>
<a href="http://www.bianmiba.com">ô</a>
<a href="http://www.shimianba.com">ʧߵƷ</a>
<a href="http://www.qdxw.net">ൺSEO</a>
<a href="http://www.zhongfengba.com">з</a>
</div>

