最近、急に増えてきた非同期処理
- script タグの async 属性
- 画像 onload
- FileAPI
- Ajax
- IndexedDB
- Web workers
- GeoLocation API
- Animation (CSS/jQuery)
この辺をすっきり書くためのフレームワーク(?), $.Deferred()
「すっきり書く」以上の機能は無いので、無くても良い物です。
以下、旧来の書き方と、$.Deferredの違いを比較しながら
( 細かい使い方については、あまり説明しませんので悪しからず )
- 今までの書き方
$.ajax({
url: './dummy.json',
type: 'GET',
dataType: 'json',
complete: function (xhr, textStatus) {
//called when complete
console.log(arguments);
},
success: function (data, textStatus, xhr) {
//called when successful
console.log(arguments);
},
error: function (xhr, textStatus, errorThrown) {
//called when there is an error
console.log(arguments);
}
});
- Deferredを使った書き方
$.ajax({
url: './dummy.json',
type: 'GET',
dataType: 'json'
}).done(function () {
// called when success
console.log(arguments);
}).fail(function () {
// called when error
console.log(arguments);
}).always(function () {
// called when always
console.log(arguments);
});
あんま変わらん。
- コールバックを引数で投げ込む
function waitCallback(sec, options, callback) {
setTimeout(function () {
callback();
}, sec * 1000);
}
waitCallback(3, {}, function () {
console.log(arguments);
});
- コールバックをDeferrdで
function waitDeferred(sec, options) {
var deferred = $.Deferred();
setTimeout(function () {
deferred.resolve(options);
}, sec * 1000);
return deferred.promise();
}
waitDeferred(3, {}).done(function (data) {
console.log(arguments);
});
逆に長くなった。
promise で返されるオブジェクトは、Deferred から resolved, rejected のメソッドを使えなくした物。 「初期化/セッティングが完了して、後はイベントの実行待ち」の意味。
処理1が終わったら処理2
waitCallback(3, {}, function () {
console.log("done1");
waitCallback(2, {}, function () {
console.log("done2");
});
});
- Deferred で
waitDeferred(3).then(function (data) {
console.log("done1");
return waitDeferred(2);
}).done(function (data) {
// 上の then の戻り値の promise へのコールバック
console.log("done2");
});
- then, done の方が直感的で読みやすい?
- 3つとかつなげると違うかも。
- 終わった処理をフラグにして、共通の関数の中で判定
// 終わったかフラグ
var p1End = false,
p2End = false;
function callback(data) {
if (p1End && p2End) {
console.log('p1 & p2 end');
}
}
var promise1 = $.ajax({
url: './dummy.json?v=1',
type: 'GET',
dataType: 'json',
success: function () {
p1End = true;
callback();
}
});
var promise2 = $.ajax({
url: './dummy.json?v=2',
type: 'GET',
dataType: 'json',
success: function () {
p2End = true;
callback();
}
});
- Deferred
var promise1 = $.ajax({
url: './dummy.json?v=1',
type: 'GET',
dataType: 'json'
});
var promise2 = $.ajax({
url: './dummy.json?v=2',
type: 'GET',
dataType: 'json'
});
$.when(promise1, promise2).done(function () {
console.log(arguments);
});
これは、確実にDeferred使った方が良さそう
- Deferredを使った方が良いとき
- 複数処理を並列、順番で走らせる
- 複数の処理を、状況に応じて組み替えるとき
例えば
- FBのログインチェック
- してなかったらログイン
- ログイン終わったらタイムラインを呼び出す
- してたらタイムラインを呼び出す
- してなかったらログイン
みたいな、ややこしい状態遷移態遷移の時
$('element')
.css()
.attr();
普段のjQueryは全部同じインスタンスを返してチェインするが
waitDeferred(3)
.then(function (data) { return waitDeferred(2); })
.done(function (data) {});
ここは別のオブジェクトでチェインしている。
then は一個目の wait、done は二個目の wait の戻り値。
http://d.hatena.ne.jp/aoe-tk/20110515/1305471586