初心者向けのjQuery入門講座|デザイナー向けのJavaScriptライブラリ

このエントリーをはてなブックマークに追加
索引
Core:コアとなる仕組み
Selectors:セレクタ
Attributes:属性
Traversing:対象の変更
Manipulation:操作
CSS:スタイルシート
Events:イベント
Effects:演出効果
Ajax:xml等との連携
Utilities:ユーティリティ
Data:データ
Miscellaneous:諸々
Deferred:処理管理
Callbacks:コールバック
Internals:内部処理

jQuery.deferred( )deferredオブジェクトの作成

構文

deferredオブジェクトを作成する返値:deferredオブジェクト
jQuery.deferred( [function] )ver1.5〜
※deferredオブジェクトを作成する前に実行したい処理がある場合は引数にfunctionを設定します。

機能

deferredオブジェクトはv1.5で追加され、非同期処理であるアニメ処理や通信処理を監視し管理しやすくします。もう少し具体的に説明すると「指定した処理が正常に終わったら〜してね、失敗したら〜してね」という処理を実現します。

deferredオブジェクトとpromiseオブジェクト

deferredオブジェクトでは「どの様な時に正常終了」とし「どの様な時に失敗」なのかを設定します。
その際に外部から簡単に正常終了や失敗の操作をされては困ります(変数が操作されないようにローカル変数にするのと同じです)。ですので通常はdeferredオブジェクトから、正常終了や失敗の操作ができないpromiseオブジェクトを作成して利用します。「正常に終わったら〜してね」等というのを「約束」にたとえpromiseオブジェクトと名付けたのだと思います。

deferredオブジェクト
処理管理の大元で、promiseオブジェクトはdeferredオブジェクトから作成されます。
jQueryではjQuery.whenメソッドpromiseメソッドで簡単にpromiseオブジェクトが作成できるため、deferredオブジェクトを意識することは少ないと思います。
promiseオブジェクト
状態(後述)を操作ができないdeferredオブジェクトと考えてください。操作できないということは、間違って操作される危険性も低いので、通常はdeferredオブジェクトからpromiseオブジェクトを作成して利用します。→参考:google検索「カプセル化

ちなみにpromiseメソッドで利用できない、状態を変化させるメソッドとは以下の6つです。
resolve, reject, notify, resolveWith, rejectWith, notifyWith

jqXHRオブジェクト

Ajax通信関連のメソッドが返すjqXHRオブジェクトはpromiseオブジェクトを内包しているため、deferredオブジェクトのメソッドを利用することができます(内包しているのはpromiseオブジェクトなので、状態を変化させるメソッドは利用できません)。
→リファレンス:Ajax目次

3つの状態

deferred(promise/jqXHRを含む)オブジェクトは処理の状態に応じて以下の3を持ちます。状態の変化は「pending→resolved(正常終了)」か「pending→rejected(異常終了)」の2つだけです。一度変化したら元には戻りません。

pending
処理が完了していない状態。deferred.progressメソッドで処理中に実行する処理を設定できます。
この状態の時はnotifynotifyWithで設定された処理が実行されます。
resolved
処理が正常に終了した状態。deferred.doneメソッドで処理の完了時に実行する処理を設定できます。 deferredオブジェクトにresolve/resolveWithを利用することで、この状態になります。
rejected
処理中に問題が発生して中断した状態。deferred.failメソッドで中断時に実行する処理を設定できます。
deferredオブジェクトにreject/rejectWithを利用することで、この状態になります。

deferredオブジェクトは覚えなくても良いと思います

jQueryではdeferredオブジェクトを覚えなくても大丈夫だと思います。例えば、通信関連で便利に利用できる「jqXHRオブジェクト」はpromiseオブジェクトを含んでいるのですが、deferredオブジェクトを理解していなくても問題なく利用できると思います。

またdeferredオブジェクトを利用しなくてもjQuery.whenメソッドpromiseメソッドで簡単にpromiseオブジェクトが作成でき、ほとんどの場合それで済むと思います。なので、このページの解説は軽く確認だけして次のページのjQuery.whenメソッドをしっかりと覚えましょう。

解説

deferredオブジェクトを作成する

サンプル(deferred/01.html)を開いてbody内にbutton要素が1つあることを確認してください。続いてjQueryで以下の様にdeferredオブジェクトを作成し、変数myDeferに代入していることを確認してください。

var myDefer = $.Deferred();

deferredオブジェクトを作成したら「どの様な時に正常終了」とするかを設定します。今回はシンプルにbuttonをクリックしたら正常終了するようにしました。以下の様に、作成したdeferredオブジェクト「myDefer」にresolveメソッドを利用することで正常終了させることができます。

$("button").click(function(){
	myDefer.resolve();
});

続いて正常終了した場合の処理を設定します。これはdeferredオブジェクトにdeferred.doneメソッドを利用して設定します。今回は以下の様にアラートで「DONE!」と表示するように設定しました。

myDefer.done(function(){
	alert("DONE!");	
});

結果としてbuttonをクリックすると、正常終了して「DONE!」と表示されます。

エラー処理

大抵は正常終了だけでなく、失敗した時の処理(エラー処理)も設定します。サンプル(deferred/02.html)を開いてbody内の構成はdeferred/01.htmlと同じ事を確認してください。

jQueryは、まず以下の処理が追加されていることを確認してください。setTimeoutを利用して3秒後に失敗するようにしました。deferredオブジェクトにrejectメソッドを利用することで状態を失敗に移行できます。

setTimeout(function(){
	myDefer.reject();
},3000);

続いて失敗した時の処理を設定します。これは以下の様に、deferredオブジェクトにdeferred.failメソッドを利用して設定します。このサンプルでは「FAIL!」とアラートで表示するようにしました。

myDefer.fail(function(){
	alert("FAIL!");	
});

3つの状態で説明したように、失敗(rejected)から正常終了(resolved)になることはありません。ですので、3秒後にbuttonをクリックしても「DONE!」とは表示されません。

promiseオブジェクトとの違いを確認

機能」の項で説明したように、通常はdeferredオブジェクトからpromiseオブジェクトを作成して利用します。サンプル(deferred/03.html)を開いてbody内の構成はdeferred/02.htmlと同じ事を確認してください。

jQueryも非常に似ているのですが、以下の処理が追加されていることを確認してください。deferredオブジェクトにdeferred.promiseメソッドを利用することで、promiseオブジェクトを作成する事ができます。

var myPromise = myDefer.promise();

作成したpromiseオブジェクトを利用しているのは以下の部分です。deferred/02.htmlではdeferredオブジェクトに利用していたdeferred.doneメソッドdeferred.failメソッドをpromiseオブジェクトに利用するようにしました。

myPromise.done(function(){
	alert("DONE!");	
});
myPromise.fail(function(){
	alert("FAIL!");	
});

動作的にはdeferred/02.htmlとまったく同じですが、最初に設定した正常終了や失敗の条件が変に操作されないように、promiseオブジェクトに変換して利用するようにします。

実際にpromiseオブジェクトが状態を変更するメソッドを受け付けないことを確認します。
サンプル(deferred/03b.html)を開いてjQueryに以下の処理が追加されていること以外はdeferred/03.htmlと同じ事を確認してください。

$(document).click(function(){
	myPromise.resolve();
});

追加した処理ではdocumentをクリックしたら正常終了するようにしていますが、実際にはdocumentをクリックしてもアラートで「DONE!」とは表示されません。これはpromiseオブジェクトが状態を変更するようなメソッド(サンプルではresolveメソッド)を受け付けないためです。

クロージャを利用する

これまでdeferredオブジェクトが間違って操作されないようにpromiseオブジェクトにして利用すると説明してきましたが、作成したdeferredオブジェクト「myDefer」が操作されては元も子もありません。ここまでのサンプルでは簡単に「myDefer」にアクセス(操作)できてしまうので、クロージャを利用してアクセスできないようにします。→使い方:研究「クロージャ1〜3」

サンプル(deferred/04.html)を開いてbody内の構成はdeferred/03.htmlと同じ事を確認してください。jQueryでは、まずいかの部分を確認してください。ここでクロージャの仕組みを利用しています。

function dfdMaster(){
	var myDefer = $.Deferred();
	$("button").click(function(){
		myDefer.resolve();
	});
	setTimeout(function(){
		myDefer.reject();
	},3000);
	return myDefer.promise();
}

これまでのdeferredの設定をfunction「dfdMaster」で行い(この時点でmyDeferはローカル変数なので外部からアクセスできなくなります)、返値にpromiseオブジェクトを返すようにしたのがポイントです。

続いて以下の部分を確認してください。ここでdfdMasterを実行して、返値としてpromiseオブジェクトを受け取っています。

myPromise = dfdMaster();

後の処理はdeferred/03.htmlと同じです。promiseオブジェクトに対して正常終了した時の処理と、失敗した時の処理を設定して利用します。

myPromise.done(function(){
	alert("DONE!");	
});
myPromise.fail(function(){
	alert("FAIL!");	
});

最後に、本当にdeferredオブジェクトにアクセスできないか確認します。サンプル(deferred/04b.html)を開いて、jQueryに以下の処理が追加されていることを確認してください。

$(document).click(function(){
	//myDeferはカプセル化されているので操作されません
	myDefer.resolve();
});

documentoをクリックしたら、deferredオブジェクトに対してresolveメソッドを利用してミリやり正常終了させようとしています。しかし実際はdocumentをクリックしても機能しない(myDeferはローカル変数ですからアクセスできません)ため、アラートで「DONE!」とは表示されません。

もしdeferredメソッドを利用してオリジナルのdeferredオブジェクトを作成する場合は、このようにdeferredオブジェクト本体にはアクセスできないようにして、代わりにpromiseオブジェクトを利用します。

メモ

参考にしたサイト

以前はdeferredオブジェクトとpromiseオブジェクトの関係をよく理解できませんでした。特に「なぜdeferredオブジェクトを直接利用せず、promiseオブジェクトを作成するのか?」という点。

しかしdeferredを解説しているサイトをいくつか確認し、クロージャと合わせて利用しているのを見て、このページで説明しているような結論に至りました。

→参考サイト:Yahooデベロッパーネットワーク様「爆速でわかるjQuery.Deferred超入門