読者です 読者をやめる 読者になる 読者になる

不動産屋のラノベ読み

不動産売買営業だけどガチガチの賃貸派の人のブログ

jQuery.Deferredで非同期をもう少しマシに書くには

WEB作成

 
JavaScript - コールバック……駆逐してやる…この世から…一匹…残らず!! - Qiita
この記事、「対象読者は JavaScript道初段くらいの人です」を「初級くらいの人です」と誤読したまま読み進めてひどい目に遭いました。初段への道は遠い……!
 
ただ、もう少しマシな書き方があるなあ、と思ったので記事にします。
 

jqXHRオブジェクトは代入してから使うと見通しが良い

$.when(
    $.get("hoge.txt"), 
    $.get("piyo.txt"), 
    $.get("nyan.txt"),   // 増えた
    $.get("myon.txt"),   // 増えた
    $.get("pong.txt"),   // 増えた
    $.get("chun.txt")    // 増えた
).then(function(
    hoge, 
    piyo,
    nyan,   // 増えた
    pong,   // 増えた
    myon,   // 増えた
    chun    // 増えた
){
    console.log(hoge[0] + piyo[0] + nyan[0] + pong[0] + myon[0] + chun[0]);
});

これだとうっかり非同期処理とその結果を代入する変数の順番を間違えるようなこともありそうです。上記のコード、実は myon と pong の変数の順序が入れ替わっています。お気付きになったでしょうか。気付くわけないですよね。

JavaScript - コールバック……駆逐してやる…この世から…一匹…残らず!! - Qiita

ということなんですが、$.getの戻り値はjqXHRオブジェクトなので、それを変数に代入してしまえばいいですね。
こんな感じです。

var hoge = $.get("hoge.txt");
var piyo = $.get("piyo.txt");
var nyan = $.get("nyan.txt");
var myon = $.get("myon.txt");
var pong = $.get("pong.txt");
var chun = $.get("chun.txt");
$.when(
    hoge,
    piyo,
    nyan,
    pong,
    myon,
    chun
).then(function(){
    console.log(hoge.responseText + piyo.responseText + nyan.responseText + myon.responseText + pong.responseText + chun.responseText);
});

「なんか変数を何度も記述するのはイヤだなあ」という方は、代入は文ではなく式なので、こんな書き方をすればいいと思います。

var hoge, piyo, nyan, pong, myon, chun;
$.when(
    hoge = $.get("hoge.txt"),
    piyo = $.get("piyo.txt"),
    nyan = $.get("nyan.txt"),
    pong = $.get("pong.txt"),
    myon = $.get("myon.txt"),
    chun = $.get("chun.txt")
).then(function(){
    console.log(hoge.responseText + piyo.responseText + nyan.responseText + myon.responseText + pong.responseText + chun.responseText);
});

非同期に代入して全部終わったらそのレスポンスを出力、という直観どおりの記述になっているかと思います。
まさか「変数宣言が面倒」とか言わないですよね……!
 

直列非同期処理にはpipeメソッド

また、今回はたまたま hoge.txt の piyo.txt の読み込みは独立しているので $.when で並列に処理できますが、もし一方の処理がもう一方に依存している場合、たとえば hoge.txt には別のファイルのパスが書かれていて、次にそのパスのファイルを読まなければならない場合には並列には処理できません。その場合はさっきの書きづらいバージョンに戻るしかありません。

JavaScript - コールバック……駆逐してやる…この世から…一匹…残らず!! - Qiita

直列非同期処理で値を引き渡すには、pipeメソッドが書きやすいです。

$.get("hoge.txt").pipe(function(hoge){
    return $.get("piyo.txt", { "hoge": hoge });
}).pipe(function(piyo){
    console.log(piyo);
});

それでもまだ見にくいという方は、CoffeeScriptで書くというのはどうでしょうか。

$.get("hoge.txt").pipe(
    (hoge) -> $.get("piyo.txt", { "hoge": hoge })
).pipe(
    (piyo) -> console.log piyo
)

私はあまり使ったことがないのでよく分かりませんが、だいぶ見やすくなった気がします。