#ajax

前記

恥ずかしいことに今仕事でjQueryでばりばりAjaxを使ってますが、 実際はただjQueryの便利なAPIを使っただけで Ajaxそのものの仕組みも分かっていません。

今更ですが、その辺の基礎知識を勉強しできるだけ誰にも分かるように 自分が理解したことをメモとして残したいです。

XMLHttpRequestとは

JavaScriptなどのウェブブラウザ搭載のスクリプト言語で、サーバとのHTTP通信を行うための組み込みオブジェクト(API)である。 すでに読み込んだページからさらにHTTPリクエストを発することができ、ページ遷移することなしにデータを送受信できるAjaxの基幹技術である。 XMLHttpRequest - Wikipedia

なるほど、これがAjaxを支える基幹ですね。 JavaScriptのオブジェクトです。 名前にXMLがついていますが、XML以外のデータも扱うことができます。

XMLHttpRequestの歴史

XMLHttpRequestは、マイクロソフトがOutlook Web Access 2000のダイナミックHTMLによるウェブインターフェースに活用するため、1999年公開のInternet Explorer 5においてActiveXオブジェクトとして実装したのが始まりである[1]。その後、2001年にMozillaプロジェクトがこれと互換性のある組み込みオブジェクトをMozilla 0.9.7およびNetscape 7で実装し、アップルも2004年にSafari 1.2でMozillaと同様の組み込みオブジェクトを実装し始めた[2]。 このように徐々にInternet Explorer以外のブラウザにも実装されていったXMLHttpRequestは、2005年にAjaxによって一躍有名になった。 XMLHttpRequest - Wikipedia

ようは各ブラウザが先にXMLHttpRequestオブジェクトを実装した、 そして偉い人がAjaxを提唱してから一気に有名になった訳ですよね。

XMLHttpRequestの仕組み

AllAboutの記事に載ってた仕組みを自分で書きました。 f:id:kinopyo:20091114023141j:image XMLHttpRequestのメソッドやプロパティは多分これからも使うことはありませんが、 一応図で見て大体把握しておきましょう。 openメソッドはイニシャライズみたいな感じで、GETかPOSTか、URLなどのパラメータを受け取ります。 そしてsendメソッドによるサーバに送信する前に、onreadystatechangeイベントのコールバックでステータスを判断しresponseTextやresponseXML プロパティのデータを返す流れですね。

拡張機能から XMLHttpRequest を使いたい場合は、非同期でロードするようにすべきです。 非同期の使用法では、データを受け取ったときにコールバックを受け取ります。 そのため、リクエストが発生している間はブラウザは通常どおりに動き続けます。

XMLHttpRequestの宣言

ブラウザにより異なる。 IE では、ActiveXObject("Microsoft.XMLHTTP") を使用。 IE のバージョンによっては、ActiveXObject("Msxml2.XMLHTTP.5.0") , ActiveXObject("Msxml2.XMLHTTP.4.0") , ActiveXObject("Msxml2.XMLHTTP.3.0") , ActiveXObject("Msxml2.XMLHTTP") なども使用出来る。 Mozilla 系ブラウザでは、XMLHttpRequest() を使用。 http://ponpon-village.net/ajax/xmlhttp.htm

非同期通信のサンプルコード

  var req;
  if( window.XMLHttpRequest){
    req = new XMLHttpRequest();
  }else if(window.ActiveXObject){
    try {
      req = new ActiveXObject("MSXML2.XMLHTTP");
    } catch (e) {
      req = new ActiveXObject("Microsoft.XMLHTTP");
    }
  }
  if (req) {
    req.open('GET', 'http://www.example.com/contents.txt');
    req.onreadystatechange = function() {
      if (req.readyState == 4) {
        document.write(req.responseText);
      }
    }
    req.send(null);
  }

req.statusはHTTPレスポンスコードで200はOK、404はよく見るNot Foundです。

注意点

  • file:/// および ftp:// は HTTP ステータスを返しません。そのため、status についてはゼロが、statusText については空文字列を返されます。
  • XMLHttpRequestは、セキュリティを考慮して、リクエストを送信できるのは同一ドメイン内に制限されています。

とりあえず自分が気になった点を書きました。 肝心なところはonreadystatechangeでのコールバックだと思います。

次回

XMLHttpRequestは同一ドメイン内に制限されていますね。 別のドメインとのやり取りはどう行うのかを次のテーマにします。 なんかJSONPとかクロスドメインなどのキーワードがよく見えますが、 その辺をはっきりしようと思います。

参考サイト:

XMLHttpRequest - Wikipedia XMLHttpRequest - MDC Ajaxはじめの一歩 XMLHttpRequest - [JavaScript]All About

#flex

Flexのtrace()はログ出力の機能です。

Javaに慣れましたので、trace()もてっきりコンソールにも

出力すると思っちゃいましたが、

実はそうではありません。

trace()を使うにはまず設定が必要です。

バージョン情報

  • Flex3 Builder: Version 3.0 (build 3.0.2.214193)
  • Flash Player: 9,0,124,0

デバッガ版のFlash Player

Flex3 Builderをダウンロードしそこに含んだ

for IE, FirefoxなどのFlash Playerを全部インストールしてください。

そのほうが万全で楽です。

既にFlash Playerがインストールされたとしても、

それがデバッガ版じゃないとダメですよ。

設定ファイルの作成

  • mm.cfgという設定ファイルを下記場所に作成
オペレーティングシステムファイルの作成場所
Macintosh OS X/Library/Application Support/Macromedia
Windows Vista/ Windows7*1C:\Users\username
Windows 2000/XPC:\Documents and Settings\username
Windows 95/98/ME%HOMEDRIVE%\%HOMEPATH%
Linux/home/username

設定ファイルの編集

作成したmm.cfgファイルを下記のように編集すれば、エラーのレポートとトレースログが有効になります。

ErrorReportingEnable=1
TraceOutputFileEnable=1

TraceOutputFileNameというログファイルの名前と出力先を指定するプロパティもありますが、

Flash Player 9 Update 以降では、TraceOutputFileName プロパティは無視され、

オペレーティングシステムごとに異なるハードコードされた場所に flashlog.txt ファイルが格納されます。

Adobe Flex3 ヘルプ

との懸念もあり、各自の環境を確認した上でお使いください。

私のFLex3 Builder, Flash 9では無効でした。

ログファイルの場所

オペレーティングシステムごとに異なるハードコードされた場所に flashlog.txt ファイルが格納されます。

オペレーティングシステムログファイルの場所
Macintosh OS X/Users/username/Library/Preferences/Macromedia/Flash Player/Logs/
Windows Vista/ Windows7*2C:\Users\username\AppData\Roaming\Macromedia\Flash Player\Logs
Windows 95/98/ME/2000/XPC:\Documents and Settings\username\Application Data\Macromedia\Flash Player\Logs
Linux/home/username/.macromedia/Flash_Player/Logs/

Windowsの方は特に隠しフォルダに注意してください。

Windows7のAppDataフォルダ、またその他WindowsのApplication Dataフォルダはデフォルトで隠しフォルダになっているため、

先にフォルダ構成で隠しフォルダを表示させてから、ログファイルを確認してください。

テストコード

<</span>?xml version=&#34;1.0&#34; encoding=&#34;utf-8&#34;?&#62;
<mx:Application xmlns:mx=&#34;http://www.adobe.com/2006/mxml&#34;
layout=&#34;absolute&#34; creationComplete=&#34;init()&#34;&#62;
<mx:Script&#62;
<![CDATA[
<private function init():void{
trace(&#34;Hello World&#34;);
}
]]&#62;
</mx:Script&#62;
</mx:Application&#62;

これでログファイルには「Hello World」と出力されるはずです。

特記事項

こういう記事はGoogleで検索すればいっぱい出てくるはずで、

自分でもう一回書こうと全然思わなかったのですが、

OSやFlash Playerのバージョンで設定内容が異なり、

私が最初見つかった幾つかのサイトでの書き方では

どう設定してもまったくログが出力されなかったのです。

アンインストールしたり、設定ファイルのエンコードまで

神経質になってしまいました。

その記事を書いた方々に別に文句はありませんが、やはり

技術記事はバージョン情報の提示を心がけましょう。

私もこれからは注意します。

参考サイト:Adobe Flex 3 ヘルプ

</div>

*1:AdobeのサイトにはWindows7は載ってません、ここは私個人で検証済み

*2:AdobeのサイトにはWindows7は載ってません、ここも私個人で検証済み

#jquery

jQueryのEventオブジェクトには

いくつかのプロパティとメソッドがありますが、

それらの定義より、実際どの場面に使えるかを重点として紹介したいと思います。

dataプロパティ

bind時に渡されたデータを保持します。

こちらの記事「jQuery bindバインド時にデータを渡す」をごらんください。

currentTargetとtargetプロパティ

最初currentTargetはイベントが発生したDOM要素だと理解していましたが、

jQueryのドキュメントを見ると似た名前でtargetの属性もあります。

そしてcurrentTargetには「バブリング」のキーワードが出てきましたので、

詳しく書きたいと思います。

サンプル:

一番大きいdiv範囲内をクリックするとそのdivのclass属性の値を返すJavaScriptです。


$(".big").bind("click",function(evt){
	alert(evt.currentTarget.className);
});

そしてHTMLコードは以こんな感じです。CSSの部分は省略しました。

直接画像を参照してください。

<div class="big">
	<div class="medium">
		<div class="small">
		</div>
	</div>
</div>

f:id:kinopyo:20091111223232j:image

alert部分のevt.currentTargetとevt.targetを入れ替えて検証します。

  • 黄色の部分をクリック
    • currentTarget:big
    • target:small
  • 緑色の部分をクリック
    • currentTarget:big
    • target:medium
  • 青色の部分をクリック
    • currentTarget:big
    • target:big

結果:

currentTargetは常にbigを表示するに対し、

targetは子要素まで「精確」表示する

どうですか、あたり?はずれ?

ここでもう一回jQueryのドキュメントを見てみましょう。

currentTarget The current DOM element within the event bubbling phase.This attribute will always be equal to this of the function.
target Contains the DOM element that issued the event. This can be the element that registered for the event or a child of it.

currentTargetは実際bind時の要素を指して、

targetはその要素および子要素まで全部含んでいると私は理解しましたが、

「バブリングフェーズ」の言葉については未だ曖昧な感じです。

そしてcurrentTargetは常にハンドラ内のthisと同じことも覚えておきましょう。

クロージャを使う際に例えばthisがほかのオブジェクトを指しても

event.currentTargetでイベントにバインドされた要素を使えます。

pageX、pageYプロパティ

  • 定義:イベント発生時のマウス座標

この「マウス座標」に興味があり、本当にイベント発生時のマウス座標か、

それともイベントが発生時のDOM要素の座標かを試しました。

jQueryサンプルのソースを使いました。

$("a").click(function(event){
	alert("Current mouse position: "
		+ event.pageX + ", " + event.pageY);
})
  • マウスでクリック:「Current mouse position: 37, 312」
  • リンクにTabでフォーカスしEnter:「Current mouse position: 0, 0」

本当にマウスによるイベントでしか座標が取れないみたいです。

応用としてはツールチップなどのプラグインで、

マウス現在の座標でオフセットして表示するイメージです。

stopPropagation()メソッド

これはバブリングに対してよく使われる用語ですね。

バブリングは言語に制限せずイベントに関する制御では必ず出てきます。

最近見たFlex3でもバブリングがあったし、

iPhoneの開発でもresponder chainの用語があり、その中身も実際はバブリングの話です。

一回だけ徹底で勉強すればどの場面でも使えるんです。

ここまで書いてちょっと疲れましたが、

自分もちゃんと決着をつけたいので、やはり書きましょう!

利用するサンプルはやはりさっきの大中小DIVです。

JavaScriptのほうのみ修正します。

$(".big").bind("click",function(evt){
	alert("big");
});
$(".medium").bind("click",function(evt){
	alert("medium");
});
$(".small").bind("click",function(evt){
	alert("small");
	evt.stopPropagation();
});
  • 黄色部分をクリックするとsmallのみが出力される
解釈

もしstopPropagationがなかったら

そもそもの動きとしてはまずイベントが発生した要素smallのイベントハンドラが処理を行います。

そしてそのsmall要素が属している親要素にイベント終了とのことを伝播し、

もしその親要素も該当イベントにバインドされたら、親のイベントハンドラが実行します。

こんな形でどんどん親にイベントを伝播するイメージがまさにバブリングという単語の意味です。

stopPropagationが実行されるとそのバブリングフェーズが終了した時点で親に対しての伝播を中止します。

自分もよくわからない「バブリングフェーズ」の用語を使っちゃいました。

なぜかって言うと、次のサンプルを先に見てみましょう。

さっきのJavaScriptを元に一つの処理だけを追加しました。

$(".big").bind("click",function(evt){
	alert("big");
});
$(".medium").bind("click",function(evt){
	alert("medium");
});
$(".small").bind("click",function(evt){
	alert("small");
	evt.stopPropagation();
});
$(".small").bind("click",function(evt){
	alert("small2");
});

これでsmallの黄色部分をクリックするとどうなるでしょうか?

small2は表示されますか?

答えは、表示されます。

なぜならさっき言ったようにstopPropagationは親に対しての伝播を中止するだけで、

同じ要素に対しての処理には影響がないとのことです。

もし同じ要素に対しても処理を中止したい場合はstopPropagation()の代わりに、

これは使います。

event.stopImmediatePropagation();

これならさっきの例で言うと、small2は出力されません。

イベントオブジェクトについてはとりあえずこの辺で終わります。

参考サイト

公式サイトのEventオブジェクトドキュメント

StackTraceサイト

#jquery

誤った使い方

例えばbind時にname変数に格納された情報を渡したい

var name = "kinopyo";
$(":button").bind("click", function(name){
  alert(name);
});

これは誤った使い方です。

alertでは望まれた「kinopyo」の文字列は表示されません。

私は最初jQueryに触れたときはこんな書き方をしたんです。


もちろんname変数とbindのコールバックは同じスコープなのでfunctionから直接name変数を参照できますが、

ここではあえて誤った使い方にしました。


実際alertでは[object Object]と表示されました。

firebugで中身をのぞいてみるとこんな感じのオブジェクトです。

このnameは一体何のか、答えはjQueryのEventオブジェクトです。

Eventオブジェクトについてはこの記事「jQuery Eventオブジェクトの詳細、バブリングの仕組み」を参照してください。

bindのAPI

bind(type, [data], fn)

  • type:click, dbclick,mousedown…などトリガーとなるイベントタイプ
  • [data]:第三パラメータのハンドラにデータを渡す。括弧は配列の意味ではなく、省略可の意味
  • fn:イベントハンドラ
  • パラメータ:jQueryのEventオブジェクト、event.dataで第二引数の[data]を参照できる

jQueryは第二パラメータに対してdataかfunctionか自動判断してます。

普段使い慣れたのはdataを省略したものでしょう。

さっきの例を修正すると、正しく「kinopyo」が表示されます。

var name = "kinopyo";
$(":button").bind("click", name, function(event){
  alert(event.data);
});

渡されるのはJavaScriptのオブジェクトです。。

つまり配列も、キー値ペアのオブジェクトも全部渡されます


参考サイト

公式サイトのbindドキュメント

StackTraceサイト

#javascript jquery

多重bind

  • 検証:一つのボタンにイベントを多重バインドした時の動き
$(input).bind('click', function() {
  alert(1);
});
$(input).bind('click', function() {
  alert(2);
});
$(input).bind('click', function() {
  alert(3);
});
  • 出力:inputのボタンをクリックするとalertで1,2,3が次々と出る
  • 結論:バインドされた順番どおり実行

一括unbind

  • 検証:上記多数バインドされた要素に対し、一括でunbind
$(input).unbind('click');
  • 出力:なし
  • 結論:一括でunbindされた

特定のイベントのみunbind

  • 検証:多数bindしたイベントの中で、特定のイベントのみunbind

バインド時のファンクションをそのまま記述(失敗)

$(input).unbind('click', function() {
  alert(2);
});
  • 出力:1, 2, 3
  • 結論:失敗

ファンクションのリテラル(リファレンス)を通してunbind

function out1() {
  alert(1);
};
function out2() {
  alert(2);
};
function out3() {
  alert(3);
};
$(input).bind('click',out1);
$(input).bind('click',out2);
$(input).bind('click',out3);
$(input).unbind('click',out2)
  • 出力:1, 3
  • 結論:ファンクションのリテラル(リファレンス変数)を通して指定したイベントのみをunbindできる、しかしこれはあらかじめファンクションを定義しておかないと駄目

名前空間を用いてbind

$(input).bind('click.1', function() {
  alert(1);
});
$(input).bind('click.2', function() {
  alert(2);
});
$(input).bind('click.3', function() {
  alert(3);
});
$(input).unbind('click.2');
  • 出力:1, 3
  • 結論:bindの第一引数でevent.namespaceと名前空間を使えばうまくunbindできる

同じの名前空間で複数のイベントにbindされた際

$(input).bind('click.namespace', function() {});
$(input).bind('blur.namespace', function() {});
$(input).unbind('.namespace');
  • 結論:名前空間指定で一括でunbindできる

一つのイベントに複数の名前空間を登録

$(input).bind('click.1.2',  function() {});
// click.1.2の名前空間にたどり着ける
$(input).trigger('click.1');
// click.1.2名前空間にたどり着ける
$(input).unbind('click.2');
  • 結論:複数の名前空間のうち、任意の一つを使えばそのイベントを選択できる

公式サイト(英語):

#jquery javascript ie

環境

  • IE6
  • jQuery1.3.2

現象

IE7、IE8、Firefox上全部OKのアプリがなぜかIE6ではエラーが頻発しました。 エラーの詳細もないので、原因がはっきりわかりません。
ソースは特に変な作り方をしてないと思うので、やはりIE6が主な原因と判断しググってみました。

調査結果

IE6でselect boxに<option>を追加した直後、 その追加した値を.valで設定しようとすると上記のエラーが発生します。 (設定する値が追加した値以外の場合、正常に設定できます)

今回のアプリではselectボックスは静的にHTMLで書いて、 jQueryでoptionをどんどんappendしてました。 やはりこの辺が怪しかったですね。
回避策としてあげられるのは.valを設定する前に.width()を一回実行することです。 信じられないぐらい、本当になおりました。 setTimeout(function () {}, 0); も回避策の一つとの選択肢もあったのですが、 なぜかこれは効きませんでした。

以下個人感想

IE6のばかばかしい動きが元凶なので、詳しく追求する気はないです。 ほかにもjQueryを使うときに注意すべきものがいっぱいあるようです。 まあ、またエラーなんか起きたらそのときまた検索すればって思います。
ウェブアプリ開発者はIE6~IE8、Firefoxなどいろいろなブラウザにも注意しながら 開発するしかないことがすごく嫌です。 この前FirefoxがやっとIE6を市場シェアを抜けて一位になった記事がありました。 (Firefox > IE6 > IE7 > IE8の感じかな、トータルではもちろIE全体がまだトップ) IE6なんかもう早く下がってほしい。
なので、ブラウザに気にしないFlex開発に興味を持ち、今勉強中です。 そこら辺の感想はまた別途で記事書きます。
ちなみに、Google分析で私のブログを見る平均時間は44秒です。 内容的にこんなに駄目なんですか。。? 44秒、、短すぎ、、

参考になったサイト

#flex

本気でFlex3を勉強しようと決めました。

「何か勉強したなら資格の形で残したい」の方針で

関連の資格をネットで調べました。

その情報をいったん整理します。

基本情報

  • 試験番号 : 9A0-082
  • 受験言語 : 日本語、英語
  • 合格点 : 67%以上
  • 問題数 : 50
  • 試験時間 : 85分
  • 受験費用 : 18,900円
  • 申し込み :ピアソンVUE
  • ガイド資料 : 認定試験準備ガイド

試験に向けて

参考サイト