Kinopyo Blog

プログラマとしてRuby, Rails, iPhone, iPad,Macなどなどと向き合う日々のログポース

Posts Tagged ‘ajax’

Ajaxとアクセス解析PVの関係

2011年02月23日

AJAXでのアクセスはPVにカウントされない、というのをこの間にミーティングで知りました。考えてみりゃ当たり前のことですが、考えたことはなかったです。。でどうするか、とのことでちょっとぐぐってみました。

結論からいうとダミーのページを指定するようにJavascript側で書く(Google Analytics前提)

<script type="text/javascript">
urchinTracker(); // デフォルト
urchinTracker("/hogehoge");
urchinTracker("/hogehoge/hege");
</script>

みたいな感じです。urchinTrackerはGoogle Analyticsが提供してくれるファンクションです。

ダミーページに階層式にするのは後で統計しやすいような工夫だそうです。

原理はこちらを参照してください:Ajaxとアクセス解析の関係を読む
(1/4):MarkeZine(マーケジン)

ちょっと長いですが、細かく解説した文章です。

こちらも役に立つかと思います。Ajaxページのアクセス解析の考え方と Google Analytics での実践 [C!]

今更のAjax基本:XMLHttpRequestについて

2009年11月13日

前記

恥ずかしいことに今仕事で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

jQueryでajax:非同期通信時、実行順番を保障する方法

2009年10月31日

前記:

この記事では多数のAJAX通信が発生した際、

「非同期」の処理順番を保障する方法を検討します。

すべては私個人の経験なので、もしこれよりもっどいい方法があれば

ぜひ教えてください。

実際この問題にぶつかった際の考えの流れで書いています。

使えない案や、懸念がある案も全部述べたので、文章が長くなってしまいました。

開発する当時はまだインターネットにつながらないので、

何の情報も取得できず、考えたんです。

後でネットで調べたらAjax Queueのプラグインが

同じことをしてくれます。

このプラグインを使った後に所感を書く予定です。





本題


AJAXはご存知だと思います。非同期通信でページをリフレッシュせずに動的に通信ができる、

リッチなウェブアプリケーションを構築する上で不欠けんな存在であります。


一方、この「非同期」というのは特徴であり、たまには厄介なことになります。

例えばajaxの処理と普通の処理の実行順序を気にするとき、

コードの書いた順番とおり実行する保障はありません。


jQueryでコードを書くと、こんな感じです。


$.ajax(option);
alert('ajax done');

ここでajax通信が終わってからalertが出るように見えますがそうとは言い切れないです。

ajax通信が終わってない段階でalertが出るかもです。

ならばどうしたらいいんですか?


一番簡単なのはjQueryが用意したコールバック関数です。

$.load(url,[data],[callback])
$.get(url,[data],[callback],[returnType])
$.getJSON(url,[data],[callback])
...

などがあります。

[data]がなければ、コールバックの関数を二番目のパラメータで書いてもOKです。

jQueryは内部的に判断してくれます。dataなのか、コールバックかを。


そして$.ajaxにはoptionでsuccessやcompleteにコールバックを設定できます。

これらを用いて上記のコードを以下のように改善できます。


$.ajax(option)の場合

.load(url,[data],[callback])
$.get(url,[data],[callback],[returnType])
$.getJSON(url,[data],[callback])
...


ここで問題2に入ります。

もし必要なajax通信が一つ以上で、すべてのajax通信が完了した後に何かの処理が実行したい場合は

どうすればいいでしょうか。


コードで書くと、こんな感じです。

$.ajax(option1);
$.ajax(option2);
$.ajax(option3);
function(){
	alert('all ajax done');
}


  • 案1:ajaxのグローバル関数


jQueryではajaxのグローバル関数と呼ばれるいくつかの関数を提供してくれました。

それらは以下のようなものです。


.ajaxComplete(handler)
.ajaxSuccess(handler)
...


これらはDOM上のどの要素にも設定でき、AJAX通信が行われる際に呼び出されます。


例えば以下のようなコードがあります。

$(document).ajaxComplete(function(){
	alert('ajax complete');
});


これはdocument要素において、何かのajax通信が完了したらパラメータのコールバックを実行する意味です。

selectorにはもっと範囲を縮むことができます。

例えば

...

のHTMLがあるとします。

$('#content').ajaxComplete(function(){
	alert('content ajax complete');
});

これならidがcontentのdivにajax通信が完了する際のコールバックを示しています。


しかしこれだけではまだ問題2を解決できません。

$.ajax(option1);
$.ajax(option2);
$.ajax(option3);
$(document).ajaxComplete(function(){
	alert('ajax complete');
});


こう書くと、任意の通信が完了したらこのajaxCompleteが呼ばれ、

ほかの二つの処理がどうなってるかはまったくわからないです。


ここで$.ajax(option)のoptionに注目しましょう。

optionにはglobalというフラグがあり、デフォルトはtrueになってます。

その役割はグローバル関数の監視対象にするかしないかです。

このフラグをfalseに設定すれば、該当のajax通信がどうなってもグローバル関数はトリガーしません。

なので、通信処理1と2のglobalフラグをfalseに設定し、最後の処理3をtrueに設定すれば、

処理3が実行完了した際、グローバルのajaxCompleteが実行されます。


改善したコードは以下になります。一部省略しました。

var option1 = {
	global : false
	// ほかのurlなどの設定
}

var option2 = {
	global : false
	// ほかのurlなどの設定
}

var option3 = {
	global : true
	// ほかのurlなどの設定
}

$.ajax(option1);
$.ajax(option2);
$.ajax(option3);
$(document).ajaxComplete(function(){
	alert('ajax complete');
});

しかし、ここで懸念事項があります。

ajax処理の間の順番はどうなるか断言できません。

つまりこういった順番で実行されたかもです。


処理1実行

処理1完了

処理2実行

処理3実行

処理3完了

グローバルの関すを呼び出す

処理2完了


軽く動作確認ではちゃんと思ったとおり1,2,3で動いていますが、

やはりその辺が気になって、やめました。


  • 案2:ajaxをラッパーした関すを作る


$.ajax(option)のoptionにはcompleteというのがあります。

successと使い方は同じで、successは通信が成功した際実行するコールバックで、

completeは完了した際のコールバックです。


なので今回思い出したのアイディアはこのcompleteに次のajax処理を指定して、

さらにその次のajaxのcomplete optionにも後のajax処理を指定したらどうでしょうか。

尻尾をどんどん噛んでいく蛇のイメージです。


(抜粋)

var option1 = {
	complete : $.ajax(option2)
}

var option2 = {
	complete : $.ajax(option3)
}

var option3 = {
	complete :function(){
				alert('ajax all complete');
	}
}

$.ajax(option1);

動作確認でOKでした。

completeオプションで前のajax通信が必ず完了した後に次のajax通信を始まることを

保障しています。

これでajaxのチェインができました。


これをちょっと綺麗にラッパーした関数を作りました。

ご覧ください。

function doOrderGuaranteedAjax(ajaxOptionArray, allCompleteHandler){
    var defaults = {
	type : "GET",
	dataType : "text",
	complete : function() {
	// 最初の要素を削除
	ajaxOptionArray.shift();
	// すべての通信が完了した場合
	if (ajaxOptionArray.length == 0 ) {
		// コールバックが設定された場合
		if (allCompleteHandler) {
			allCompleteHandler();
		}
	} else {
		// 通信配列にまだ通信が残っている場合
		option = ajaxOptionArray[0];
		// ajaxのオプションを次の通信に切り替え
		opts = $.extend({}, defaults, option);
		// 通信を開始
		$.ajax(opts);
	};
	}
};

    // 初期指定
    var option = ajaxOptionArray[0];
    var opts = $.extend({}, defaults, option);
    // 一回のみ実行
    $.ajax(opts);

};


まず$.ajax(option)のoptionを順番でpushした配列が第一パラメータで渡されます。

2~23行まではデフォルトのoptionを構築し、一回目の処理は29行から走ります。

そしてデフォルトのoptionではcompleteで実行完了した処理を配列から削除(7行)します。

配列にまだ待ち状態の処理があるならオプションを次の通信に切り替えます(14~20行)。

もし配列にある処理が全部実行完了したら、コールバックを呼びます(9~13行)。


使い方はまずオプションを一つの配列にpushし、その配列を一番目のパラメータで、

コールバックを二番目のコールバックで渡します。

var optionArray = [];
optionArray.push(option1);
optionArray.push(option2);
optionArray.push(option3);
doOrderGuaranteedAjax(optionArray, function(){
	alert('all complete');
});

arrayのpushとshiftを利用し、スタック構造を真似してます。

push() は array の最後に配列要素を加えます。

shift() は array の最初の要素を削除します。


これでファーストイン、ファーストアウトFIFOが実現し、

処理の順番が保ちます。