My Photo

« March 2014 | Main | May 2014 »

April 27, 2014

SSI覚え書き

既存のWEBアプリでSSIを使っている部分の修正をしたら、includeコマンドが実行されなくなった。
原因はパーミッションで、SSIを使っているファイルには実行権限が必要だった。
以下、SSIについて簡単にまとめた。

SSIはURLリライトと同様に、a2enmod でSSIを有効にする。

sudo a2enmod include

/etc/apache2/mods-enabled の include.load が /etc/apache2/apache2.conf 経由で読み込まれて SSI が有効になる。
.htaccess は以下

Options +IncludesNOEXEC
XBitHack on

IncludesNOEXEC はexec以外のSSIのコマンドを有効にする。
XBitHack on は text/htmlファイルでかつユーザーの実行権限があるファイルでSSIが利用できるようにする。on の他に full という値の指定できる。ただし、他のCGIなどをincludeしているものやアクセス毎に内容が変わるものには full は指定しない方が良い(参考1)。

SSIの例。

<body>
ssi.html
<pre>
<!--#echo var="DOCUMENT_URI" -->
<!--#config timefmt="%Y/%m/%d %H:%M:%S" -->
<!--#echo var="DATE_LOCAL" -->
<!--#echo var="LAST_MODIFIED" -->
</pre>
<!--#include file="footer.html" -->
</body>

出力は以下のようになる。

<body>
ssi.html
<pre>
/test/test2/ssi.html

2014/04/27 21:15:54
2014/04/27 20:59:43
</pre>
footer.html

</body>

参考ページ:
1.mod_include - Apache HTTP サーバ
2.SSI と XBitHack - 朝顔日記
3.SSI を .html ファイルで使う方法 - CMS「すぐ使えるCGI」
4.[Apache] Apache2.4系でSSIを使う digape.com
5.とほほのSSI入門

2014年初釣り

そろそろキスが釣れるかなと思って今年の初釣りに行ってきた。いつものようにボッチで。
最初は三浦市の三戸浜堤防。京急の終点、三崎口駅から結構な距離を歩く。やはり釣りには車があったほうがぜったいいなあと改めて思った。途中は台地にキャベツ畑が広がっていてのどかな風景。
10時くらいに到着。漁船が係留しているので投げ釣りができるのは堤防の先端付近だけだが、すでに先客が多数。なので堤防の中ほどで漁船の隙間から港の内側に向かってチョイ投げをした。エサは生餌ではなくガルプのワーム。
晴れていて気温は低くないが風があって結構肌寒かったので、マフラーを首に巻いて釣りをした。持っていってよかった、マフラー。
#Tシャツ1枚で釣りをしている人がいた。俺は寒がりなんだろうか?
14時まで粘ったが全くアタリなしorz
先端で釣っていた人はキス2,3匹釣れていた。また、港の外側ではアオリイカが釣れていた。
三浦半島でエギングをしている人はたくさん見かけるが、実際に釣れたのを見たのは初めてだ。いるんだな、イカ。

釣りしている途中、ネコが3匹現れた。とても愛想がいい。明らかに食べ物目当てだが^^;

三戸浜堤防から撤退し、帰る途中に横須賀市のうみかぜ公園に寄ってみた。
空いているところを見つけてちょっと投げてみたら何か釣れた。メゴチ?マゴチ?10cmない小物だったのでリリース。なんとか坊主は避けられた。
可能性のあるポイントだと思ったが、その場所のすぐ後ろで建築工事をしていて猛烈にシンナー臭い(そのために空いている)。頭が痛くなってきたので帰ることにした。
帰る途中、岸壁の南側の様子を見てきました。さびき釣りでイワシが結構釣れていた。キスがつれてるのも1回見た。

今日言った2箇所はどちらも初めて。うみかぜ公園は良い釣り場だと思う。でも回りが大型店や遊戯施設などがあって、ボッチ釣りはちょっと肩身が狭いなあ。
三戸浜堤防は今日はイマイチだったが、もっと暖かくなれば可能性がありそう。ただ、キス釣りなら堤防じゃなくて砂浜の方でもいいかも。海水浴客が来るまでなら。
キスについてはGWは釣れないこともないけどまだちょっと早いように感じた。もっと暖かくというか暑くなって、魚影が濃くなってから釣りに行けばいいんじゃないかと思った。次は6月に入ってからとか。
それとやはり早起きは重要だと。早起き自体というより、良いポイントを取ることが。

あと、どうでもいいが「ボッチ釣り」と「ボッチチェリ」は似ている。
20140426_01
20140426_02
20140426_03


April 22, 2014

URLリライトの復習とIE11のUser-Agent

以前の関連する記事:UbuntuサーバのApache2でURLリライトを試してみる

以前の記事でURLリライトの設定を書いた。最初書いた設定は想定とは異なるURLに書き換えられてしまい、修正して想定どおりのURL書き換えがされるようになった。しかし、どういう仕組みで動作が変わったのか理解していなかった。
あれからもう少し調べて、自分なりの解釈をまとめてみた。リファレンスに書いてある「事実」と自分なりの「解釈」がごっちゃになっていて信頼性は低い。

リダイレクトとURLリライトの違い・使い分け

URLが指し示している内容と違うものを返す方法には、URLリライトの他にリダイレクトがある。
リダイレクトは、例えばサイト全体が www.newsite.jp に移転したので前のサイトに来たアクセスを新しいサイトの方に転送した場合には次のように書く。

Redirect permanent / http://www.newsite.jp/

リダイレクトとURLリライトについて、表にしてみた。

リダイレクトURLリライト
URL書き換えられる。ブラウザのアドレスバーのURLは最終的にアクセスした先のURLになる。書き換えられない。ブラウザのアドレスバーのURLは変わらない。(設定によっては書き換えられる)
レスポンスステータスコードは301(Moved Permanently)。ヘッダーのLocationに転送先のURLが入る。ステータスコード、メッセージはURLリライトで書き換えられた最終的なURLのものとなる。
mod_rewritemod_rewriteがなくても利用できる。インストールされて有効になっていなければ使えない。
条件の設定出来ない。出来る。かなり複雑な条件も設定できる。

URLリライトというのはmod_rewriteの機能の事だから、mod_rewriteがなければ使えないのは当然。
mod_rewrite がインストールされていなければリダイレクトを使うしかない。また、サイトをファイル名・ディレクトリ構成をそっくりそのまま移転した場合もリダイレクトを使うのが簡単。
それ以外の場合、例えば色々条件を付けて転送したい場合はURLリライトを使う。

なぜURLリライトが無限ループしなくなったのか

まず、言葉の定義。
.htaccess や apache2 設定ファイルの "<Directory>" 内に書かれた一連の書き換えルールを「ルールセット」と呼ぶ。<br /> RewriteRuleの末尾に "[" と "]" に囲まれてRとかLとか書いてあるのがRewriteRuleのフラグ。フラグの個々の意味は後で説明する。

次にURLリライトの動作について。
URLリライトはルールセットを使用して次のように動作する。

  1. 書き換え前のURLに書き換えルールを順番に適用して書き換えを試みる。
  2. ルールにマッチするものがなく、URLが書き換えられなかった場合、書き換えは終了。
  3. 書き換えによって外部サイトに転送される場合、書き換えは終了。
  4. それ以外、つまりURLが元のURLと同じサイト内のURLに書き換えられた場合、書き換え後のURLを書き換え前のURLとして1に戻る。

つまり、外部サイトに転送されるか、URLがルールにマッチせずに書き換えの必要がなくなるまで何度もルールセットが適用される。

上記を踏まえて、前の記事で書いたURLリライトの設定が以下である。

RewriteEngine on
RewriteBase /test/rewrite/

RewriteRule ^top.html - [L]

RewriteRule ^index.html$|^$ top.html [L]
RewriteRule ^y.*$ http://www.yahoo.co.jp/ [R,L]

RewriteCond %{HTTP_USER_AGENT} MSIE
RewriteRule ^.+$ ie.html [L]

最初に書いた設定は4行目のルールがなかったために、思ったような書き換えにならなかった。
IEで "http://<ホスト名>/test/rewrite/index.html" にアクセスした場合、/test/rewrite/top.html が表示されると想定していたが、実際には /test/rewrite/ie.html が表示された。
なぜ4行目のルールがあると想定通りの動きになるのか。
ポイントは4行目のルールにある "-" である。"-" はURLのマッチングだけを行い置換は行わないという特殊な置換対象である。
URLリライトは以下のように行われる。
1回目のルールセット適用:6行目の index.html が top.html に書き換えられる。このルールにはLフラグがあるのでルールセット適用はここで終了する。
2回目のルールセット適用:4行目のルールに top.html がマッチするが、置換対象が "-" なのでURLは書き換えられない。このルールにはLフラグがあるのでルールセット適用はここで終了する。今回のルールセット適用ではURLの書き換えは起こらなかったので、URLリライト自体が終了する。
最終的にURLは "http://<ホスト名>/test/rewrite/top.html" に書き換えられる。
もし4行目がコメントアウトされていると、2回目のルールセット適用において、ブラウザがIEなので9,10行目のルールによって top.html が ie.html に書き換えられてしまう。

ちなみに IE11からUser-Agentに "MSIE" というのが含まれなくなった(参考14)ので、上記のRewriteCondの条件はIE11では使えない。

RewriteRuleの書式

RewriteRuleの書式は以下である。

RewriteRule パターン 置換対象 [[フラグ]]

フラグを複数指定する場合はカンマで区切って指定する。
フラグの一部を下表に示す。

RewriteRuleのフラグ
フラグ説明
Lここで書き換え処理を中止し、後続のルールによってそれ以上書き換えられることを防止する。
R[=code] 外部サイトにリダイレクトする。codeはレスポンスコード。省略された場合は302(Found)。
NC 大文字小文字を区別しない。

ページを外部サイトに移転した場合、RewriteRuleに "R=301" というフラグを付けてレスポンスコードを301(Moved Permanently)とするとよい。
上記以外のフラグは参考1,2などを参照。

RewriteCond

RewriteCondディレクティブはRewriteRuleの条件を定義する。RewriteCondの直後のRewriteRuleの条件となる。複数のRewriteCondはフラグでORを指定しなければANDで結合される。 書式は以下である。

RewriteCond テスト文字列 条件パターン [[フラグ]]

テスト文字列には "%{変数名}" の形式で変数を使うことが出来る。この前記や下記のルールセットのRewriteCondではHTTPヘッダのUser-Agentを "%{HTTP_USER_AGENT}" として使用している。その他の変数については参考1,2,10などを参照。
また、RewriteRuleと同様にフラグが指定可能である。書き方も同様で "[" と "]" の間に、数のフラグを書く場合はカンマ区切りで書く。

RewriteCondのフラグ
フラグ説明
NC 大文字小文字を区別しない。
OR 条件をORで結合する。

RewrteCondを使ったルールセットの例を下記に示す。実用を考えたものではない。

RewriteEngine on

RewriteRule ^bbb.html - [L]
RewriteRule ^ccc.html - [L]

RewriteCond %{HTTP_USER_AGENT} "Windows NT" [NC]
RewriteCond %{HTTP_USER_AGENT} Trident [NC]
RewriteRule ^.*a.html$ bbb.html

RewriteRule ^.*b.html$ ccc.html

上記のルールセットにおいて、1つめのルールはRewriteCondによってブラウザがWindowsのIE(IE8以降)であることが条件となる。RewriteCondは直後のRewriteRuleにのみ係るので、2つ目のルールはRewriteCondによる条件は適用されない。
よってIE8以降のIEで "/xxa.html" とアクセスした場合、"xxa.html" → "bbb.html" → "ccc.html" と書き換えられる。
他のブラウザの場合は "/xxa.html" は書き換えられない

参考ページ:
・RedirectとURLリライトの違い・使い分け
1..htaccessによるリダイレクト徹底解説 - Cherry Pie Weblog
2.Rewrite/Redirect - Yuta.Kikuchiの日記

・リダイレクトについて
3.htaccess解説/リダイレクト(サイトの引越し)

・mod_rewriteのリファレンス
4.mod_rewrite - Apache HTTP Server
5.Apache module mod_rewrite

・URLリライトの設定について
6.mod_rewriteの考え方。 - こせきの技術日記
…一部リンクが切れているが、RewriteRuleとRewriteCondの関係の説明がわかりやすい。
7.Apache Rewrite 設定のサンプル(1) : 個別のURLを転送する | OSCALOG
8..htaccess ファイルで mod_rewrite の設定をする時の注意点 | ミヤビッチの穴
9., mod_rewriteによるURLの書換えに関するメモ - 忘れたときに備えた記録(2007-07-18)

・RewriteCondについて
10.Apache RewriteCond の基礎知識 | WEB ARCH LABO

・RewriteCondによる条件の例
11.htaccessによるPC・スマートフォンの振り分け転送
12.Apache でアクセスを制限する時間帯を設定する | ポンタの技術日記
13.ApacheウェブサーバーのRewrite設定で使える正規表現サンプル集 | Web担当者Forum

・IE11のUser-Agentについて
14.IE11のユーザエージェント問題 - 開発者側でできる対策 (判定方法の変更/互換性モードの利用) - ふろしき.js

April 14, 2014

PHPメモ038:PHPのswitchの比較は厳密な比較ではない

PHPの罠にはまった。
以下のような感じのコードを書いた。

switch ($type) {
case '01':
	$code = 'a';
	break;
case '02':
	$code = 'b';
	break;
default:
	$code = 'x';
}

$type が "01", "02", "99" の場合、$code は それぞれ "a", "b", "x" となった。想定通り。
しかし、$type が "1" の時に $code は "x" となると思っていたが、実際は "a" だった。
原因は、PHPのswitchの比較が厳密な比較(===)ではなく緩い比較(==)であるということだった。

以下のように書けば想定していた動作になるが、これなら else if で書いた方がいいなあ。

switch (TRUE){
case $type === '01':
	$code = 'a';
	break;
case $type === '02':
	$code = 'b';
	break;
default:
	$code = 'x';
}

今回の件で改めて、CとJavaで育った人間からするとPHPは不可解、直感的にわかりにくいと思った。switchのほかには3項演算子のこととか。
switch の件はリファレンスにちゃんと「緩い比較だよ」って書いてあるけど、既に他の言語をある程度使える人がわざわざswitchやら3項演算子の仕様を細かく確認しないでしょう。で、罠にはまって「あれ?」ってことになる。
言語仕様だけじゃなくて、ライブラリもなんだか名前や仕様が統一されていないように思う。isset() と is_int()など型を調べる関数で、なんでアンダースコアがあったりなかったりするのか。isset は関数じゃなくて言語構造だけど、でも似たようなジャンルのものでなぜこういう差異があるのかわからない。
他には配列操作関数の array_merge() と array_push()。array_merge() は結果が引数の配列への副作用として現れるが、array_push() は引数の配列には副作用がなく結果は返り値として現れる。この違いにちゃんとした理由があるのなら知りたい。

PHPはWebアプリを作る際には他の言語より少ない記述量で書ける点で便利ではあるが、言語としては一貫性というか統一感がなくて美しさに欠けるように思う。

参考ページ:
PHP: switch - Manual
れぶろぐ - [PHP] PHP の switch 文は怖くて使えない
PHP言語仕様のバグ - れぷそる・ふぁいやぁ・ぶれぇど

April 10, 2014

Deferredで無限ループしてポーリング

以前の関連する記事:
jQueryで非同期な処理が終わるのを待つにはDeferredを使う
Deferredの復習
Deferredの復習2:jQueryのAjax関数はPromiseを実装したjqXHRを返す

「一定間隔でポーリングして処理の進行状況をチェックし、処理中ならば『処理中です』と画面に表示し、処理が終わったらポーリングをやめて『処理が完了しました』と表示させる。」というようなことをやりたい。 参考ページにDeferredを使った無限ループの実装があったので、それをベースにして考えてみた。
まず、スリープ関数とその使用例。

function mySleep(time) {
  return (
    function() {
      var dfd = $.Deferred();
      setTimeout(
        function() {
          console.log("resolve() [" + time + "sec]:" + new Date().toLocaleString());
          dfd.resolve();
        },
        time * 1000);
      return dfd.promise();
    });
}

function outputLog(msg) {
  return (
    function() {
      console.log("log: " + msg + " : " + new Date().toLocaleString());
    });
}

function testFunc() {
  $.ajax({
      url: "http://testhoge.jp/get_status.php",
      type: "POST",
      dataType: "json"
    })
  .then(
    function(data, status, xhr) {
      console.log("resolved: status=" + status + "[" + xhr.status
                  + "] data.status=" + data.status
                  + " :" + new Date().toLocaleString());
    },
    function(xhr, status, thrown) {
      console.log("rejected: status=" + status + "" + xhr.status
                  + "] :" + new Date().toLocaleString());
    })
  .then(mySleep(5))
  .done(outputLog("done"))
  .fail(outputLog("fail"));
}

上記の testFunc はリクエストが成功すると38行目の then に渡された mySleep(5) が実行された5秒間待ち、それから outputLog("done") が実行される。
リクエストが失敗すると mySleep(5) はスキップされ、ただちに outputLog("fail") が実行される。

これを踏まえて、「処理が終わるまでポーリング」の実装(script要素内)を以下に示す。

$(function() {
	polling();
});

function mySleep(time) {
  return (
    function() {
      var dfd = $.Deferred();
      setTimeout(
        function() {
          dfd.resolve();
        },
        time * 1000);
      return dfd.promise();
    });
}

// 3秒毎にポーリング
function polling() {
  $.ajax({
      // 処理の状態を取得するサービスにアクセス
      url: "http://testhoge.jp/get_status.php",
      type: "POST",
      dataType: "json"
    })
  .then(
    function(data, status, xhr) {
      // 取得したデータの内容によってDeferredの状態を変更する
      var d = $.Deferred();
      if (data.status === "completed") {
        d.reject();
      } else {
        d.resolve();
      }
      
      // Promiseを返す
      return d.promise();
    })
  .then(mySleep(3))
  .done(polling)
  .fail(
    function () {
      $("#running").hide();   // 「実行中」を非表示にする
      $("#completed").show(); // 「完了」を表示する
    });
}

初期状態で id="runnning" のdiv要素が表示されていて id="completed" のdiv要素は非表示になっている。
画面のロードが完了すると polling が実行されてリクエストが実行される。レスポンスが帰ってくると33行目の then に渡された関数が実行される。その関数はレスポンスの値が "completed" でなければresolvedなDeferredから作成したPromiseを返す。すると、次の then に渡された mySleep(3) が実行されて3秒間待った後、次の行の done に渡された polling が再帰呼び出しされる。このように3秒間隔でポーリングされる。
レスポンスが "completed" の場合はrejectedなPromiseが返されるので、mySleep(3) は実行されず、fail に渡された関数がただちに実行されて、実行中であることを示している部分を非表示にして、完了したことを知らせる要素を表示する。

別にDeferredを使わなくても setInterval() でいいような気もするが、setInterval() には指定したcallback関数の処理に時間がかかる場合に問題があるというような記事もちらほら見かける。詳しいことは setInterval() を使ったことがないのでよくわからないが。

参考ページ:
jQuery.Defferredを使ったdone無限ループとSleepで簡単ポーリング - それマグで!

April 09, 2014

jQueryのAjax関数はPromiseを実装したjqXHRを返す

以前の関連する記事:
jQueryで非同期な処理が終わるのを待つにはDeferredを使う
Deferredの復習

jqXHR

jQueryのAJAX関数(ajax(),get(),put())はjqXHRオブジェクトを返す。jqXHRはPromiseを実装している。
このjqXHRはAjax関数によるリクエストが成功するとresolvedになり、失敗するとrejectedになる。よって下記の2つのコードは同様な動作となる。

// success,errorプロパティを使用
$.ajax({
    url: "http://testhoge.jp/test.php",
    type: "POST",
    data: data,
    success: function(data, status, xhr) {
      console.log("success: status=" + status + "[" + xhr.status + "]");
    },
    error: function(xhr, status, thrown) {
      console.log("error: status=" + status + "[" + xhr.status + "]");
    },
    dataType: "text"
  });
// Deferredのdone(),fail()を使用
$.ajax({
    url: "http://testhoge/test.php",
    type: "POST",
    data: data,
    dataType: "text"
  })
.done(
  function(data, status, xhr) {
    console.log("done: status=" + status + "[" + xhr.status + "]");
  })
.fail(
  function(xhr, status, thrown) {
    console.log("fail: status=" + status + "[" + xhr.status + "]");
  });

参考ページ:
Deferredまとめ | Qrefy - jQuery日本語リファレンス
Ajaxまとめ | Qrefy - jQuery日本語リファレンス
jQuery モダンAjaxな書き方を目指して -Deferredを使ったAJAX- - Hack Your Design!
結局jQuery.Deferredの何が嬉しいのか分からない、という人向けの小話 - Qiita

April 06, 2014

Deferredの復習

以前の関連する記事:jQueryで非同期な処理が終わるのを待つにはDeferredを使う

以前、jQueryのDeferredについての記事を書いて、大雑把には理解できた。
Deferredについて最もわかりやすい解説は参考1,2だと思う。概念的には決して難しくないのだが、Deferredのメソッドが各々どんな引数を取り、どんな値を返すのかとか、日本語のリファレンスを読んでも読み取れなかった(書いてなかった?)こととかがある。
そういうところをところをあらためてまとめた。

DeferredとPromise

Deferred.promise() が返すPromiseオブジェクトとは何か。以前の記事では参考3から下記の引用を示した。

Promiseは、ユーザがDeferredの状態の変更を防ぐための、Deferredのメソッドのサブセット(then,done,fail等)を提供する。

で、それってつまりどういうことかというと、参考2から引用すると

.promise()という謎のメソッドが書かれていますが、これはDeferredオブジェクトから.resolve()や.reject()といった「状態を変更するメソッド」を取り除いたサブセットを返します。Deferredオブジェクトを直接返してしまうと、受け取った側で状態を変更できてしまい、非同期処理そのものが本当に終わったのかどうか保証が取れなくなります。これを防ぐため、.promise()によるクリーニング作業が必要になるわけです。

とのこと。つまり、Promiseオブジェクトは done() や fail() は持ってるけど resolve() や reject() は持っていない。なのでDeferredではなくPromiseを渡しておけば、渡した先で勝手に状態を変更されたりしなくて安心、ってこと。なるほど。

Diferred.then

Diferred の then() はdone() と fail() を一度にできて便利、というだけではなかった(jQuery1.8以降)。
done() と fail() が返す値は元のPromiseそのものである(Deferredではなくて?)。単純に return this している。
対して、then() は新たなPromiseを作成して返す。
また、then() に普通の関数を渡した場合とPromiseを返す関数を渡した場合も動作が違う。
これら違いについて下記の3つの関数を使って具体的に説明する。

/**
 * 2秒後にコンソールに出力する。必ずresolveする。
 * Promiseを返す。
 * @returns Promise
 */
function delayHello() {
	var d = new $.Deferred;
	setTimeout(function() {
		console.log('Hello!');
		d.resolve();
	}, 2000);
	return d.promise();
}

/**
 * 3秒後に(以下同文)
 */
function delayHello3000() {
	var d = new $.Deferred;
	setTimeout(function() {
		console.log('Hello!');
		d.resolve();
	}, 3000);
	return d.promise();
}

function hello() {
  console.log('Hello! sync');
}

下記は done() でメソッドチェーンを作成している。

delayHello()
.done(delayHello)
.done(delayHello);

この場合、2行目のdone() が返すのは最初の delayHello() が返すPromise(p1と呼ぶ)なので、2行目の done() も3行目の done() も同じp1に対する処理である。よって、p1がresolvedになると2行目の done() に渡された delayHello と 3行目 done() に渡された delayHello が間を置かずに続けて実行される。
consoleには以下のように出力される。

Hello!  ←2秒後
Hello!  ←4秒後
Hello!  ←4秒後

下記は then() に普通の関数を渡してメソッドチェーンを作成している。

delayHello()
.then(hello)
.then(hello);

then() に普通の関数を渡すと、then() が返すPromiseは前のPromiseとは異なるオブジェクトであるが、状態は引き継ぐ。上のコードでは最初の delayHello() が返すPromiseがresovedになると、2行目の then() が返すPromiseも直ちにresolvedとなり、結果として2行目の hello() と3行目の hello() は間を置かず続けて実行される。
consoleには以下のように出力される。

Hello!       ←2秒後
Hello! sync  ←4秒後
Hello! sync  ←4秒後

下記は then() にPromiseを返す関数を渡してメソッドチェーンを作成している。

delayHello()
.then(delayHello)
.then(delayHello);

2行目の then() が返すPromiseは(p3と呼ぶ)、最初の delayHello() が返すPromise(p1と呼ぶ)と2行目の then() に渡された delayHello() が返すPromise(p2と呼ぶ)の両方と関連のあるPromiseで、p1 と p2 の両方がresolovedになると p3 もresolvedになる。よって、3つのdelayHello() は2秒の間隔を開けて順番に実行される。
consoleには以下のように出力される。

Hello!  ←2秒後
Hello!  ←4秒後
Hello!  ←6秒後

結局、then() で処理を連結するとなにがうれしいかというと、「順番に非同期処理を行う」コードを「コールバック地獄」(参考2)にならず直感的に書けるということのようだ。
「処理を直列に連結」という説明がイメージ的にわかりやすい。

$.when

when() は引数に1個以上のオブジェクトを取り、渡されたオブジェクトをまとめたPromiseを返す。
引数がDeferredまたはPromiseの場合、引数のオブジェクトがすべてresolvedになると、返されたPromiseもresolovedになる。引数のオブジェクトのうち1つでもrejectedになると、返されたオブジェクトはrejectedになる。
引数がDeferred、Promiseではない場合、resolvedなものとして扱われる。
when() は、then() による「直列の連結」に対して「並列の連結」と言われる。when() を利用するケースとしては、複数の非同期処理を実行し、すべての非同期処理が終了したところで新たな処理を行うことが考えられる。

$.when(delayHello(), delayHello3000())
.done(hello);

上記のコードでは、delayHello() の返すPromiseと delayHello3000() が返すPromiseの両方がresolovedになると、done() で渡された hello() が実行される。以下のように出力される。

Hello!       ←2秒後
Hello! 3000  ←3秒後
Hello sync   ←3秒後

参考ページ:
1.爆速でわかるjQuery.Deferred超入門 - Yahoo! JAPAN Tech Blog
2.JavaScriptとコールバック地獄 - Yahoo! JAPAN Tech Blog
3.Types | jQuery API Documentation
4.$.when() - jQuery API Documentation 日本語訳
5.jQuery.DeferredとかjQuery.whenの使い方について - 一から勉強させてください( ̄ω ̄;)

« March 2014 | Main | May 2014 »

May 2017
Sun Mon Tue Wed Thu Fri Sat
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      
無料ブログはココログ

日本blog村

  • にほんブログ村 IT技術ブログへ
  • にほんブログ村 アニメブログへ
  • にほんブログ村 サッカーブログ アルビレックス新潟へ

好きな音楽家

メモ

XI-Prof