<?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>Screw-Axis &#187; Javascript</title>
	<atom:link href="http://screw-axis.com/category/tips/javascript-tips/feed/" rel="self" type="application/rss+xml" />
	<link>http://screw-axis.com</link>
	<description>flexible, elastic and principled.</description>
	<lastBuildDate>Thu, 08 Apr 2010 01:00:18 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>[js] Ajax通信がF5で更新されない場合</title>
		<link>http://screw-axis.com/2009/08/12/ajax_xhr_f5/</link>
		<comments>http://screw-axis.com/2009/08/12/ajax_xhr_f5/#comments</comments>
		<pubDate>Wed, 12 Aug 2009 12:40:02 +0000</pubDate>
		<dc:creator>nao58</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Ajax]]></category>
		<category><![CDATA[Cache]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://screw-axis.com/?p=689</guid>
		<description><![CDATA[画像やスクリプトなどの外部ファイル取り込みを高速化するために、キャッシュ制御は不可欠です。
しかし、設定をうっかりすると(あるいは、しないと)、キャッシュが強すぎて全くデータが更新されないような場合があります。
今回のキ [...]


No related posts.]]></description>
			<content:encoded><![CDATA[<p><img src="http://farm1.static.flickr.com/164/435720036_61f24af0d8_m.jpg" alt="fortuneteller" title="fortuneteller" width="240" height="178" class="alignright size-full" style="margin-left: 5px;" />画像やスクリプトなどの外部ファイル取り込みを高速化するために、<a href="/2009/06/06/web-google-page-speed%e3%81%a7%e3%82%b5%e3%82%a4%e3%83%88%e3%82%92%e9%ab%98%e9%80%9f%e5%8c%961/">キャッシュ制御</a>は不可欠です。<br />
しかし、設定をうっかりすると(あるいは、しないと)、キャッシュが強すぎて全くデータが更新されないような場合があります。<br />
今回のキーワードは、「IE」と「F5キー」、そして「XMLHttpRequest」。<br />
「<a href="http://www.amazon.co.jp/gp/product/487311361X?ie=UTF8&#038;tag=paiitbla-22&#038;linkCode=as2&#038;camp=247&#038;creative=1211&#038;creativeASIN=487311361X">ハイパフォーマンスWebサイト</a>」の著者であるStevesSuders氏のblogで紹介された「<a href="http://www.stevesouders.com/blog/2009/08/11/f5-and-xhr-deep-dive/">F5 and XHR deep dive</a>」を検証してみます。<br />
<span id="more-689"></span></p>
<h5>「F5」でXHR通信結果が更新されない</h5>
<p>通常、キャッシュが設定された外部ファイル取り込みは、その期限が来るまでは再通信されません。しかしブラウザをF5やCtrl+rなどで明示的にリロードした場合はその限りではなく、ファイルの再取得が行われるのが一般的です。<br />
しかし、キャッシュ指定の条件によっては、XMLHttpRequestを用いた、いわゆるAjax通信時が発生しなくなってしまうと<a href="http://blog.httpwatch.com/2009/08/07/ajax-caching-two-important-facts/comment-page-1/">HttpWatchの記事</a>で伝えられました。<br />
これを検証するために、簡単なプログラムを作ってみます。</p>
<h5>検証プログラムの説明</h5>
<p>まずは、取り込まれるjsファイルを用意します。<br />
サーバサイドで毎回ジェネレートされる、現在時刻を指定された要素に出力するだけのスクリプトです。</p>
<p><a href="http://dev.screw-axis.com/sandbox/f5_cache/js.php?id=hoge" target="_blank">検証用スクリプト</a></p>
<p>呼び出す度に日時が更新されることが分かると思います。</p>
<p>そして必要なのはキャッシュコントロール。<br />
パケット監視などが出来る人は見ていただけばわかるのですが、パラメータに応じて次のようなヘッダを付与します。</p>
<dl>
<dt>cache=1</dt>
<dd>キャッシュ有効。Expiresを30日後にし、Cache-Controlのmax-ageも30日間に設定します。</dd>
<dt>cache=-1</dt>
<dd>キャッシュ無効。Expiresを30日前にし、Cache-Controlのmax-ageは0とします。</dd>
<dt>cache=0</dt>
<dd>キャッシュ指定無し。ExpireもCache-Controlも指定しません。</dd>
</dl>
<p>ついでに、画像も用意してみました。同様にサーバサイドで現在時刻の画像を作成して返します。キャッシュ制御も同じです。</p>
<p><a href="http://dev.screw-axis.com/sandbox/f5_cache/img.php">検証用画像</a></p>
<p>これを、テスト用のHTMLで取り込みます。<br />
スクリプトは、scriptタグによる単純な取り込みと、XMLHttpRequestによるAjax通信の2種類。画像はimgタグで指定しています。<br />
前述の3種類のキャッシュ制御を行うページは、次の通りです。</p>
<ul>
<li><a href="http://dev.screw-axis.com/sandbox/f5_cache/test.php?cache=-1">キャッシュ無効</a></li>
<li><a href="http://dev.screw-axis.com/sandbox/f5_cache/test.php?cache=1">キャッシュ有効</a></li>
<li><a href="http://dev.screw-axis.com/sandbox/f5_cache/test.php?cache=0">キャッシュ指定無し</a></li>
</ul>
<p>これで、ページを開いた時の時刻(正確には、サーバがリクエストを受け付けた時刻)が表示されるはずです。リロードや再訪問時に、キャッシュが効いていれば日時はキャッシュされた時のままになります。</p>
<p>順に見ていきましょう。</p>
<h5>キャッシュ無効の場合</h5>
<table class="grid" cellspacing="0" style="width: 400px;">
<tr>
<th></th>
<th colspan="3">通常遷移</th>
<th colspan="3">F5リロード</th>
</tr>
<tr>
<th></th>
<th>Image</th>
<th>Script</th>
<th>XHR</th>
<th>Image</th>
<th>Script</th>
<th>XHR</th>
</tr>
<tr>
<th>Chrome2</th>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
</tr>
<tr>
<th>FF3.0</th>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
</tr>
<tr>
<th>FF3.5</th>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
</tr>
<tr>
<th>Opera9</th>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
</tr>
<tr>
<th>Opera10</th>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
</tr>
<tr>
<th>IE6</th>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
</tr>
<tr>
<th>IE7</th>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
</tr>
<tr>
<th>IE8</th>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
</tr>
<tr>
<th>Safari3</th>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
</tr>
</table>
<p>いずれの場合も期待通り、キャッシュは全くききませんでした。<br />
ページ遷移を行った場合も、F5でリロードした場合も、全て最新に更新されます。</p>
<h5>キャッシュ有効の場合</h5>
<table class="grid" cellspacing="0" style="width: 400px;">
<tr>
<th></th>
<th colspan="3">通常遷移</th>
<th colspan="3">F5リロード</th>
</tr>
<tr>
<th></th>
<th>Image</th>
<th>Script</th>
<th>XHR</th>
<th>Image</th>
<th>Script</th>
<th>XHR</th>
</tr>
<tr>
<th>Chrome2</th>
<td>キャッシュ</td>
<td>キャッシュ</td>
<td>キャッシュ</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
</tr>
<tr>
<th>FF3.0</th>
<td>キャッシュ</td>
<td>キャッシュ</td>
<td>キャッシュ</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
</tr>
<tr>
<th>FF3.5</th>
<td>キャッシュ</td>
<td>キャッシュ</td>
<td>キャッシュ</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
</tr>
<tr>
<th>Opera9</th>
<td>キャッシュ</td>
<td>キャッシュ</td>
<td>キャッシュ</td>
<td>更新</td>
<td>更新</td>
<td>キャッシュ</td>
</tr>
<tr>
<th>Opera10</th>
<td>キャッシュ</td>
<td>キャッシュ</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
</tr>
<tr>
<th>IE6</th>
<td>キャッシュ</td>
<td>キャッシュ</td>
<td>キャッシュ</td>
<td>更新</td>
<td>更新</td>
<td>キャッシュ</td>
</tr>
<tr>
<th>IE7</th>
<td>キャッシュ</td>
<td>キャッシュ</td>
<td>キャッシュ</td>
<td>更新</td>
<td>更新</td>
<td>キャッシュ</td>
</tr>
<tr>
<th>IE8</th>
<td>キャッシュ</td>
<td>キャッシュ</td>
<td>キャッシュ</td>
<td>更新</td>
<td>更新</td>
<td>キャッシュ</td>
</tr>
<tr>
<th>Safari3</th>
<td>キャッシュ</td>
<td>キャッシュ</td>
<td>キャッシュ</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
</tr>
</table>
<p>動作が分かれました。<br />
通常にページ遷移を行った場合は、Opera10を除き一律にキャッシュが使われる期待通りの動作です。(Opera10はまだbetaのため、最終的にどういった仕様になるかは不明です)<br />
F5などでリロードを行うと、画像やscript要素で取り込んだものは、いずれも再読み込みされます。<br />
しかしXMLHttpRequestでの通信は、ChromeやFFでは再通信が行われるのに対し、IEとOpera9ではそのままキャッシュが有効になってしまいました。これはCtrl+F5のようなスーパーリロードを用いても、変わりません。</p>
<h5>キャッシュ指定無しの場合</h5>
<table class="grid" cellspacing="0" style="width: 400px;">
<tr>
<th></th>
<th colspan="3">通常遷移</th>
<th colspan="3">F5リロード</th>
</tr>
<tr>
<th></th>
<th>Image</th>
<th>Script</th>
<th>XHR</th>
<th>Image</th>
<th>Script</th>
<th>XHR</th>
</tr>
<tr>
<th>Chrome2</th>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
</tr>
<tr>
<th>FF3.0</th>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
</tr>
<tr>
<th>FF3.5</th>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
</tr>
<tr>
<th>Opera9</th>
<td>キャッシュ</td>
<td>キャッシュ</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
</tr>
<tr>
<th>Opera10</th>
<td>キャッシュ</td>
<td>キャッシュ</td>
<td>キャッシュ</td>
<td>更新</td>
<td>更新</td>
<td>キャッシュ</td>
</tr>
<tr>
<th>IE6</th>
<td>更新</td>
<td>更新</td>
<td>キャッシュ</td>
<td>更新</td>
<td>更新</td>
<td>キャッシュ</td>
</tr>
<tr>
<th>IE7</th>
<td>更新</td>
<td>更新</td>
<td>キャッシュ</td>
<td>更新</td>
<td>更新</td>
<td>キャッシュ</td>
</tr>
<tr>
<th>IE8</th>
<td>更新</td>
<td>更新</td>
<td>キャッシュ</td>
<td>更新</td>
<td>更新</td>
<td>キャッシュ</td>
</tr>
<tr>
<th>Safari3</th>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
<td>更新</td>
</tr>
</table>
<p>かなり無軌道になっています。Operaに至っては、通常のページ遷移でも動作に違いが出てしまいました。</p>
<h5>ETagについて</h5>
<p>StevesSuders氏の検証ではETagについても含まれています。<br />
今回は検証結果を見やすくするために、レスポンス304については確認していません。<br />
氏のページによれば、Safari4はIf-Modified-Sinceを送らずに常に再送信されてしまうようです。</p>
<h5>まとめ</h5>
<ol>
<li>Expiresを指定しないことは、動作を全く制御しないのと同じこと。可能な限りきちんと、用途にあわせてキャッシュの制御を行うべきです。</li>
<li>Ajax通信でキャッシュをされたくない場合(多くの場合、この用途でしょう)、Expiresを過去に指定してキャッシュを無効にしましょう。</li>
<li>或いは、通信にエポックタイムのようなユニークなIDをパラメータに付与し、キャッシュできないようにするのも良い方法です。</li>
<li>Ajax通信をキャッシュしたい場合、Expiresをキャッシュしたい期間、きちんと指定しましょう。ただし、その際にはF5でリロードしても更新されないブラウザがいることを知っておきましょう。</li>
<li>Operaを対応ブラウザにするならば、バージョン10がどのような仕様になるか注意しておきましょう。</li>
</ol>


<p>No related posts.</p>]]></content:encoded>
			<wfw:commentRss>http://screw-axis.com/2009/08/12/ajax_xhr_f5/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[js] 外部ファイルロードを便利、高速に</title>
		<link>http://screw-axis.com/2009/07/15/js-degrading-script-tags/</link>
		<comments>http://screw-axis.com/2009/07/15/js-degrading-script-tags/#comments</comments>
		<pubDate>Wed, 15 Jul 2009 05:48:53 +0000</pubDate>
		<dc:creator>nao58</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://screw-axis.com/?p=667</guid>
		<description><![CDATA[2週間ほど前に入手したSteve Sounders氏の新刊「Even Faster Web Sites」ですが、ようやく本格的に読み始めました。
前の「ハイパフォーマンスWebサイト ―高速サイトを実現する14のルール」 [...]


Related posts:<ol><li><a href='http://screw-axis.com/2009/05/17/javascript%e3%81%aenull%e3%81%a8undefined%e3%81%a8false%e3%81%a80%e3%81%a8%e7%a9%ba%e6%96%87%e5%ad%97%e3%81%a8/' rel='bookmark' title='Permanent Link: [Javascript] nullとundefinedとfalseと0と空文字と'>[Javascript] nullとundefinedとfalseと0と空文字と</a></li>
<li><a href='http://screw-axis.com/2009/06/11/web-google-page-speed%e3%81%a7%e3%82%b5%e3%82%a4%e3%83%88%e3%82%92%e9%ab%98%e9%80%9f%e5%8c%963/' rel='bookmark' title='Permanent Link: [Web] Google Page Speedでサイトを高速化(3)'>[Web] Google Page Speedでサイトを高速化(3)</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p><img src="http://farm1.static.flickr.com/170/467072434_c8c1e1468b_m.jpg" alt="tricky" title="tricky" width="240" height="160" class="alignright size-full" style="margin-left: 5px;" />2週間ほど前に入手したSteve Sounders氏の新刊「<a href="http://www.amazon.co.jp/gp/product/0596522304?ie=UTF8&#038;tag=paiitbla-22&#038;linkCode=xm2&#038;camp=247&#038;creativeASIN=0596522304">Even Faster Web Sites</a>」ですが、ようやく本格的に読み始めました。<br />
前の「<a href="http://www.amazon.co.jp/gp/product/487311361X?ie=UTF8&#038;tag=paiitbla-22&#038;linkCode=as2&#038;camp=247&#038;creative=1211&#038;creativeASIN=487311361X">ハイパフォーマンスWebサイト ―高速サイトを実現する14のルール</a>」は発刊前にネット上で読んでいたのでスルーしてしまいましたが、今回はちゃんと購入。前のものが基本をしっかりと抑えた王道的内容だったのに比べて、比較的トリッキーなテクニックが増えているように思います。</p>
<p>今回は本書の5章から「へー」と思った、外部スクリプトを他のファイルのロードを妨げることなく取得し、なおかつそのファイルのロードが終わった際に後続のスクリプトが実行されるための方法(複雑)を確認してみます。<br />
<span id="more-667"></span></p>
<h5>SCRIPTタグを減らすテクニック</h5>
<p>この技法はまず、jQueryの作者であるJohn Resig氏のblogポスト <a href="http://ejohn.org/blog/degrading-script-tags/">Degrading Script Tags</a> に端を発します。<br />
まず、次のコードを見て下さい。</p>
<pre name="code" class="html">
&lt;script src="jquery.js"&gt;&lt;/script&gt;
&lt;script&gt;
  jQuery(document).ready(function($){
    $("div").text("loaded!");
  });
&lt;/script&gt;
</pre>
<p>これを、次のように書けたら幸せだよね、という話。</p>
<pre name="code" class="html">
&lt;script src="jquery.js"&gt;&lt;/script&gt;
  jQuery("div").text("loaded!");
&lt;/script&gt;
</pre>
<p>これなら、SCRIPTタグが少なくて済むし、コードの依存関係もハッキリする。srcに記述されたファイルのロードが失敗したら中身のコードが実行されない形なら、万が一の場合にもスクリプトエラーにならずに済むと。</p>
<p>次のようなコードを外部ファイル(この例で言えばjquery.js)の最後に加えれば、これが実装できます。</p>
<pre name="code" class="javascript">
(function(){
var scripts = document.getElementsByTagName("script");
var curScript = scripts[ scripts.length - 1 ];

if ( curScript.executed )
  return;

// ... jQuery ...

curScript.executed = true;
var script = curScript.innerHTML;
if ( script ) {
  jQuery(document).ready(function(){
    jQuery.globalEval( script );
  });
}
})();
</pre>
<p>もちろんこれは、jQuery以外のライブラリでも適用可能な、非常にクールな手法です。<br />
正直なところ、自分は最初のこのポストが投稿された際にはそれほど感銘を受けなかった記憶があります。それは「スクリプトのロードと実行が連動する」点に私が着目できていなかったからで、単にscriptタグを減らせるシンタックス程度の認識しかありませんでした。<br />
今回改めて読み返してみて、直観的な良い記述方法だなと思いました。</p>
<h5>他ファイルのロードブロック問題</h5>
<p>見たように素晴らしいテクニックなのですが、この方法にもまだパフォーマンスの観点から改善の余地があるとSteve Sounders氏は指摘しています。<br />
それが、<a href="/2009/06/11/web-google-page-speed%e3%81%a7%e3%82%b5%e3%82%a4%e3%83%88%e3%82%92%e9%ab%98%e9%80%9f%e5%8c%963/">スクリプトのダウンロードが他の外部ファイルのダウンロードをブロックしてしまう問題</a>の回避についてです。</p>
<p>前述のテクニックはjsファイルのロードについては通常の方法であるため、ブロックは発生してしまいます。これを避け、なおかつロード完了とスクリプト実行がきちんと連動するように改良されたスクリプトが、<a href="http://stevesouders.com/efws/degrading-script-tag.php?t=1247630376">こちら</a>で紹介されています。</p>
<pre name="code" class="javascript">
function init(){
  jQuery("div").text("loaded!");
}

var domscript = document.createElement('script');
domscript.src = "jquery.js";
if ( -1 != navigator.userAgent.indexOf('Opera')){
  domscript.innerHTML = 'init();';
}else{
  domscript.text = 'init();';
}
document.getElementsByTagName('head')[0].appendChild(domscript);
</pre>
<p>この呼び出し方と前述のテクニックを組み合わせることで、高速な外部ファイル呼び出しと、そのロード完了に依存するスクリプトの記述が可能になります。</p>
<p>但し、この方法を使うには外部ファイル側に自要素の中身をコールバック(?)する仕組みを埋め込まなければならず、汎用的に使うのは難しくなってしまいます。<br />
将来的にこの記述をブラウザ側がサポートしてくれた場合であればまだしも、現時点では同書の別項で紹介されている<a href="http://stevesouders.com/efws/script-onload.php">Onload技法</a>の方が優れているとしています。<br />
こちらの検証は、また機会があれば。</p>


<p>Related posts:<ol><li><a href='http://screw-axis.com/2009/05/17/javascript%e3%81%aenull%e3%81%a8undefined%e3%81%a8false%e3%81%a80%e3%81%a8%e7%a9%ba%e6%96%87%e5%ad%97%e3%81%a8/' rel='bookmark' title='Permanent Link: [Javascript] nullとundefinedとfalseと0と空文字と'>[Javascript] nullとundefinedとfalseと0と空文字と</a></li>
<li><a href='http://screw-axis.com/2009/06/11/web-google-page-speed%e3%81%a7%e3%82%b5%e3%82%a4%e3%83%88%e3%82%92%e9%ab%98%e9%80%9f%e5%8c%963/' rel='bookmark' title='Permanent Link: [Web] Google Page Speedでサイトを高速化(3)'>[Web] Google Page Speedでサイトを高速化(3)</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://screw-axis.com/2009/07/15/js-degrading-script-tags/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[js] 演算子+と-の速度差と最速ループ</title>
		<link>http://screw-axis.com/2009/06/17/js-speed-of-sum-subtract/</link>
		<comments>http://screw-axis.com/2009/06/17/js-speed-of-sum-subtract/#comments</comments>
		<pubDate>Tue, 16 Jun 2009 15:53:00 +0000</pubDate>
		<dc:creator>nao58</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://screw-axis.com/?p=576</guid>
		<description><![CDATA[先週はGoogle Developer Day 2009に行ってきまして、非常に有意義なセッションもあれば、それなりのものもありましたが。
今回は個人的に最も良かったパメラさんのGoogle Maps高速化セッションから [...]


No related posts.]]></description>
			<content:encoded><![CDATA[<p><img src="http://farm1.static.flickr.com/48/125489887_124cf772c5_m.jpg" alt="math" title="math" width="240" height="158" class="alignright size-full" style="margin-left: 5px;" />先週はGoogle Developer Day 2009に行ってきまして、非常に有意義なセッションもあれば、それなりのものもありましたが。</p>
<p>今回は個人的に最も良かったパメラさんのGoogle Maps高速化セッションから、大量マーカーの効果的なプロット方法&#8230;は、また今度時間がある時にして、その際に彼女がポロっと漏らした「+=は-=に比べて遅いし」を軽く検証してみました。（FOXでアメリカン・アイドルを観ながら）</p>
<p>検証は、ループカウンタをアップしていく/ダウンしていく方法で比較しています。</p>
<p>※2009.09.27<br />
検証プログラムの問題を指摘いただき、末尾に追加してあります。</p>
<p><span id="more-576"></span></p>
<h5>検証プログラム</h5>
<pre name="code" class="javascript">
/* (1) sum */
var s = get_ms();
for(var i=0; i&lt;arr.length; ++i){
  arr[i] = i;
}
var e = get_ms();
dump(e-s);

/* (2) subtract */
var s = get_ms();
for(var i=arr.length; i&gt;0; --i){
  arr[i] = i;
}
var e = get_ms();
dump(e-s);
</pre>
<p>get_msはミリ秒を取得する関数、dumpは結果を出力する関数として用意しました。arrは、500,000個の添え字を持つ単純な配列です。<br />
これを、公平を期すために同一プロセス内で交互に実行します。結果の単位はミリ秒となります。</p>
<h5>結果</h5>
<p>[Firefox3.0.1]</p>
<pre>
(1) 107
(2) 92
(1) 106
(2) 92
(1) 107
(2) 90
(1) 107
(2) 92
</pre>
<p>足し算、引き算の順です。</p>
<p>[Internet Explorer 7]<br />
IEはFFに比べてこの実験では遅く、しかも「スクリプトの実行に時間が&#8230;」というエラーが出てしまいます。止める方法はあるのでしょうが、調べるのも面倒なので、配列のサイズを200,000に減らし、繰り返し回数も減らしてあります。</p>
<pre>
(1) 110
(2) 94
(1) 125
(2) 93
(1) 110
(2) 93
</pre>
<h5>まとめ</h5>
<p>疑う余地はなく、減算の方が高速という結果が出ました。FF2やIE8などはTV前のここの環境には無いので試していませんが、傾向としては充分だと思います。<br />
特に大きなループでは可能ならば和算よりも減算を使うようにするのが良さそうです。</p>
<p>なお、カウントダウンでのループが可能なアルゴリズムであれば、比較演算も省略できる次の形の方が、より高速でした。</p>
<pre name="code" class="javascript">
/* (3) while-subtract */
var s = get_ms();
var i=arr.length;
while(--i){
  arr[i] = i;
}
var e = get_ms();
dump(e-s);
</pre>
<p>[Firefox3.0.1]</p>
<pre>
(1) 110
(2) 91
(3) 77
(1) 106
(2) 92
(3) 77
</pre>
<p>コード量も少なく、お勧めの記述です。</p>
<h5>2009.09.27追記</h5>
<p>コメント欄で指摘をいただきました。<br />
初歩的なミスで、lengthの評価回数が釣り合っておりませんでしたので、改めてやってみます。</p>
<pre name="code" class="javascript">
var len = arr.length;

/* (1) sum */
var s = get_ms();
for(var i=0; i&lt;len; ++i){
  arr[i] = i;
}
var e = get_ms();
dump(e-s);

/* (2) subtract */
var s = get_ms();
for(var i=len; i&gt;0; --i){
  arr[i] = i;
}
var e = get_ms();
dump(e-s);
</pre>
<h5>結果</h5>
<p>[Firefox3.5.3] (500,000ループ)</p>
<pre>
(1)100
(2)97
(2)100
(1)95
(2)100
(1)97
</pre>
<p>[Internet Explorer 8] (200,000ループ)</p>
<pre>
(1)47
(2)62
(1)47
(2)62
(1)47
(2)63
</pre>
<p>[Chrome 2] (5,000,000ループ)</p>
<pre>
(1)29
(2)26
(1)29
(2)26
(1)28
(2)25
</pre>
<h5>再まとめ</h5>
<p>結果、FF3.5やChrome2では傾向は変わらないものの、その差は縮まりました。<br />
また、IE8では寧ろ加算の方が速くなっています。<br />
前回テストした際のバージョンに該当するブラウザが手元に無いので比較実験になっていませんが、加減算の速度差は気にするほどではないと言えるかもしれません。</p>


<p>No related posts.</p>]]></content:encoded>
			<wfw:commentRss>http://screw-axis.com/2009/06/17/js-speed-of-sum-subtract/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>[Javascript] nullとundefinedとfalseと0と空文字と</title>
		<link>http://screw-axis.com/2009/05/17/javascript%e3%81%aenull%e3%81%a8undefined%e3%81%a8false%e3%81%a80%e3%81%a8%e7%a9%ba%e6%96%87%e5%ad%97%e3%81%a8/</link>
		<comments>http://screw-axis.com/2009/05/17/javascript%e3%81%aenull%e3%81%a8undefined%e3%81%a8false%e3%81%a80%e3%81%a8%e7%a9%ba%e6%96%87%e5%ad%97%e3%81%a8/#comments</comments>
		<pubDate>Sat, 16 May 2009 15:55:37 +0000</pubDate>
		<dc:creator>nao58</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://screw-axis.com/?p=134</guid>
		<description><![CDATA[
table.matrix{
  margin-left: 20px;
  border-top: 1px solid #000;
  border-left: 1px solid #000;
}
table.matri [...]


Related posts:<ol><li><a href='http://screw-axis.com/2009/05/20/php-%e8%ab%96%e7%90%86%e6%bc%94%e7%ae%97%e5%ad%90%e3%80%8cand-or%e3%80%8d%e3%81%a8%e3%80%8c-%e3%80%8d%e3%81%ae%e9%81%95%e3%81%84/' rel='bookmark' title='Permanent Link: [PHP] 論理演算子「and, or」と「&#038;&#038;, ||」の違い'>[PHP] 論理演算子「and, or」と「&#038;&#038;, ||」の違い</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<style>
table.matrix{
  margin-left: 20px;
  border-top: 1px solid #000;
  border-left: 1px solid #000;
}
table.matrix th{
  border-right: 1px solid #000;
  border-bottom: 1px solid #000;
}
table.matrix td{
  text-align: center;
  border-right: 1px solid #000;
  border-bottom: 1px solid #000;
}
</style>
<p>大抵の、特に変数の型宣言を行わないタイプの言語では、型の異なる値の条件式は悩みの種です。<br />
Javascriptもご他聞に洩れずというか、undefinedとnullが異なる分だけ更にややこしくなっているようです。<br />
暗黙の型変換で痛い目にあわないよう、ちょっと実験してまとめてみます。<br />
実験にはとりあえず、手っ取り早いので <a href="http://www.billyreisinger.com/jash/index.html">Jash</a> を使用。<br />
一緒に試してみるならば、<a href="javascript:(function(){document.body.appendChild(document.createElement('script')).src='http://www.billyreisinger.com/jash/source/latest/Jash.js';})();">こちら</a>のBookmarkletをクリックしてコンソールに入力しながら読むとわかりやすいかもしれません。</p>
<h5>nullとundefined</h5>
<p>nullとundefined。たまに「同じもの？」と聞かれることもあるので、とりあえず確かめて見ます。</p>
<pre class="jash">
>> null==undefined
true
</pre>
<p>あれ、同じでしょうか？<br />
<span id="more-134"></span></p>
<pre class="jash">
>> null===undefined
false
</pre>
<p>もちろん違います。<br />
しかし、== 演算子で比較する限りは「同じ」と言ってもよいようです。<br />
では、実際は何が違うのでしょうか？typeofで確認してみます。</p>
<pre class="jash">
>> typeof null
object
>> typeof undefined
undefined
</pre>
<p>nullはobjectなんですね。<br />
根本的に型が違う（undefinedには型が無い？）ようです。</p>
<h5>演算子: ==</h5>
<p>ではこの == という曖昧な演算子について検証してみます。<br />
登場人物はfalseと、それと等しくなりそうな7つの値「undefined」「null」「&#8221;(空文字)」「0(数値のゼロ)」「&#8217;0&#8242;(文字列としてのゼロ)」「&#8221;\n&#8221;(改行)」「&#8221; &#8220;(スペース)」。<br />
先ほどのように、それぞれを == で結んでみましょう。</p>
<pre class="jash">
>> false==null
false
</pre>
<p>全て試したマトリックスが次のものです。（undefはundefined）</p>
<table class="matrix" cellspacing="0" style="width: 400px;">
<tr>
<th></th>
<th>false</th>
<th>undef</th>
<th>null</th>
<th>&#8221;</th>
<th>0</th>
<th>&#8217;0&#8242;</th>
<th>&#8220;\n&#8221;</th>
<th>&#8221; &#8220;</th>
</tr>
<tr>
<th>false</th>
<td style="color:blue">true</td>
<td style="color:red">false</td>
<td style="color:red">false</td>
<td style="color:blue">true</td>
<td style="color:blue">true</td>
<td style="color:blue">true</td>
<td style="color:blue">true</td>
<td style="color:blue">true</td>
</tr>
<tr>
<th>undef</th>
<td style="color:red">false</td>
<td style="color:blue">true</td>
<td style="color:blue">true</td>
<td style="color:red">false</td>
<td style="color:red">false</td>
<td style="color:red">false</td>
<td style="color:red">false</td>
<td style="color:red">false</td>
</tr>
<tr>
<th>null</th>
<td style="color:red">false</td>
<td style="color:blue">true</td>
<td style="color:blue">true</td>
<td style="color:red">false</td>
<td style="color:red">false</td>
<td style="color:red">false</td>
<td style="color:red">false</td>
<td style="color:red">false</td>
</tr>
<tr>
<th>&#8221;</th>
<td style="color:blue">true</td>
<td style="color:red">false</td>
<td style="color:red">false</td>
<td style="color:blue">true</td>
<td style="color:blue">true</td>
<td style="color:red">false</td>
<td style="color:red">false</td>
<td style="color:red">false</td>
</tr>
<tr>
<th>0</th>
<td style="color:blue">true</td>
<td style="color:red">false</td>
<td style="color:red">false</td>
<td style="color:blue">true</td>
<td style="color:blue">true</td>
<td style="color:blue">true</td>
<td style="color:blue">true</td>
<td style="color:blue">true</td>
</tr>
<tr>
<th>&#8217;0&#8242;</th>
<td style="color:blue">true</td>
<td style="color:red">false</td>
<td style="color:red">false</td>
<td style="color:red">false</td>
<td style="color:blue">true</td>
<td style="color:blue">true</td>
<td style="color:red">false</td>
<td style="color:red">false</td>
</tr>
<tr>
<th>&#8220;\n&#8221;</th>
<td style="color:blue">true</td>
<td style="color:red">false</td>
<td style="color:red">false</td>
<td style="color:red">false</td>
<td style="color:blue">true</td>
<td style="color:red">false</td>
<td style="color:blue">true</td>
<td style="color:red">false</td>
</tr>
<tr>
<th>&#8221; &#8220;</th>
<td style="color:blue">true</td>
<td style="color:red">false</td>
<td style="color:red">false</td>
<td style="color:red">false</td>
<td style="color:blue">true</td>
<td style="color:red">false</td>
<td style="color:red">false</td>
<td style="color:blue">true</td>
</tr>
</table>
<p>さて、いかがでしょう。<br />
かなりの無秩序さにゲンナリです。<br />
かろうじて文字列同士はキャストが行われない分だけ理解しやすいですが&#8230;つまり、ここで挙げた文字列は全てfalseや0と等価になるものの、お互いは等価にはならないと。</p>
<h5>演算子: ===</h5>
<p>では、型まで含めた === 演算子を用いた場合はどうでしょう。</p>
<pre class="jash">
>> false===0
false
</pre>
<p>これは、予想通り全ての異なる値間で false となりました。<br />
厳密な比較を行うのならば、やはりこれを使うのが良さそうです。</p>
<h5>演算子: !</h5>
<p>では、if文の中での暗黙の条件式はではどうでしょう。<br />
前項で false との等価比較だったので、あわせてここは「!」を付けた条件式に真と評価されるかどうかを試してみます。<br />
わかりにくいですね。つまり例えば undefined のテストであれば、次のような式で試したということです。</p>
<pre class="jash">
>> (!undefined ? true : false)
true
</pre>
<p>先ほどと同じ値を用いて試したのが、次の表です。</p>
<table class="matrix" cellspacing="0" style="width: 100px;">
<tr>
<th>false</th>
<td style="color:blue">true</td>
</tr>
<tr>
<th>undefined</th>
<td style="color:blue">true</td>
</tr>
<tr>
<th>null</th>
<td style="color:blue">true</td>
</tr>
<tr>
<th>&#8221;</th>
<td style="color:blue">true</td>
</tr>
<tr>
<th>0</th>
<td style="color:blue">true</td>
</tr>
<tr>
<th>&#8217;0&#8242;</th>
<td style="color:red">false</td>
</tr>
<tr>
<th>&#8220;\n&#8221;</th>
<td style="color:red">false</td>
</tr>
<tr>
<th>&#8221; &#8220;</th>
<td style="color:red">false</td>
</tr>
</table>
<p>なんと、 == 演算子のどの列とも合致しない結果です。<br />
つまり、こういうことなのですね。</p>
<pre class="jash">
>> hoge=null
null
>> (hoge==false?true:false)
false
>> (!hoge?true:false)
true
</pre>
<h5>まとめ</h5>
<p>では、実際にはどうコーディングすれば安全なのでしょうか。<br />
動きをある程度ちゃんと把握していれば、あとは用途にあわせて&#8230;という言い方に結局はなると思います。<br />
しかし、型が怪しい場合は極力 == は使わない方が良いと言えそうです。</p>
<p><strong>未定義の変数を調べる場合は typeof を使う</strong></p>
<pre>( typeof v == 'undefined' )</pre>
<p><strong>型を意識して正確に比較するなら === を使う</strong><br />
当然のことながら。<br />
しかし実のところ、Javascriptでこういったケースはあまり多くないと思います。</p>
<p><strong>テキストボックスに入力があるかを確かめる場合</strong><br />
これは、よく見ると結構難問です。<br />
純粋に文字列が全く入っていないことを確かめるならば、=== を使えば確実です。</p>
<pre>( text.value==='' )</pre>
<p>しかし、この場合は空白や改行が入っただけでも条件をパスしてしまいます。<br />
trim関数が標準で無いので、これはそれなりに厄介。<br />
では、意外とこれではどうでしょう。</p>
<pre>( text.value==false )</pre>
<p>問題は、「0」や「000」と入力された場合に未入力と判定されてしまうことです。<br />
ここはやはり、正規表現などを用いるのが良さそうです。</p>
<p>まとめてみましたが、あんまりスッキリしませんでした。</p>


<p>Related posts:<ol><li><a href='http://screw-axis.com/2009/05/20/php-%e8%ab%96%e7%90%86%e6%bc%94%e7%ae%97%e5%ad%90%e3%80%8cand-or%e3%80%8d%e3%81%a8%e3%80%8c-%e3%80%8d%e3%81%ae%e9%81%95%e3%81%84/' rel='bookmark' title='Permanent Link: [PHP] 論理演算子「and, or」と「&#038;&#038;, ||」の違い'>[PHP] 論理演算子「and, or」と「&#038;&#038;, ||」の違い</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://screw-axis.com/2009/05/17/javascript%e3%81%aenull%e3%81%a8undefined%e3%81%a8false%e3%81%a80%e3%81%a8%e7%a9%ba%e6%96%87%e5%ad%97%e3%81%a8/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
