JavaScript
jQuery

jQuery Deferredまとめ

More than 1 year has passed since last update.

参照

よく分かるjQuery Deferred http://amzn.to/1SkAQXn

学習内容

  • .done()と.fail()
  • Promise
  • 非同期と同期処理
  • Deferred
  • .then()
  • $.when()
  • $.Callbacks()

Deferred

  • 非同期処理を直列に記述、実行するための仕組み。
  • 非同期処理で、複数の処理を、指定した順番で実行することができる。

Promise

  • Jquery ver.1.5からAjax関係のメソッドは「Promise」を返すようになった
  • Ajaxが無事終了した時、「Promise」に、コールバック関数を、done()というメソッドを使って登録する。
  • Ajaxが異常終了した時、「Promise」に、コールバック関数を、fail()というメソッドを使って登録する。

スクリーンショット 2016-03-25 14.56.23.png

before.js
function onSuccess(){
    console.log("成功");
}
function onFailure(){
    console.log("失敗");
}

$.ajax("ajax1.php",{
    success: onSuccess,
    error: onFailure
});

Promiseを使って書くと

after.js
var promise = $.ajax("ajax1.php");
promise.done(onSuccess);
promise.done(onFailure);

Promiseのメリットは何か?

2つのコールバック関数を呼び出す場合

ビフォー

before.js
$.ajax("ajax1.php",{
    success: function(){

    //この中で2つを呼び出す
    onSuccess1();
    onSuccess1();
    }
});

  • コールバック関数の呼び出しが1箇所で集中管理されている。

アフター

  • promiseさえ手元にあれば、どこでもコールバック関数を登録することができる。
after.js
var promise = $.ajax("ajax1.php");
promise.done(onSuccess1);
promise.done(onSuccess2);

メソッドチェーンで書いた場合

$.ajax("ajax1.php").done(onSuccess1, onSuccess2);

引数を受け取る

var promise = $.ajax({
    url: "ajax1.php"
});

promise.done(function (data, textStatus, jqXHR){
        //dataでサーバからのデータを受け取る
});

非同期

$.ajax({
    url:'ajax1.php',//5秒待たされるとする
    success:function(){
        console.log("AJAX1終了");
    }
});

$.ajax({
    url:'ajax2.php',//2秒待たされるとする
    success:function(){
        console.log("AJAX2終了");
    }
});

console.log("読み込み終了");

//読み込み終了
//AJAX2終了
//AJAX1終了
  • 非同期処理は、一旦処理待ちとして後回しになる。並列的に処理を行う。

Deferred

  • 鍵付きのタイムカプセル
var defer = $.Deferred();
defer.done(onSuccess1);
defer.done(onSuccess2);
defer.fail(onFailure);

defer.resolve(); //成功1 成功2

3つの状態

  • pending 未開封
  • resolved 無事開封
  • rejected 異常開封

関数内でDeferredを生成して、Promiseを返すパターン

function preload(url){
    var defer = $.Deferred(),//Deferredを生成
        img = new Image();

    img.onload = function(){
        defer.resolve();
    };
    img.onerror = function(){
        defer.reject();
    };
    img.src = url;

    return defer.promise();//Deferredをpromiseに変換
}


var promise = preload("logo.gif");

promise.done(function(){
    console.log("画像の先読み完了");
});

promise.fail(function(){
    console.log("画像の先読み失敗");
});

アニメーションでDeferredを使う

function onSuccess1(){
    console.log("アニメ終了");
}

function startAnim(){
//関数内でDeferredを生成して、Promiseを返すパターンは同じ
    var defer = $.Deferred();

    $("#div1").hide(1000, defer.resolve);//コールバックを指定
    return defer.promise();
}

var promise = startAnim();
promise.done(onSuccess1);
  • Div要素を1秒かけて.hide()するサンプル
  • .hide()の第2引数に、アニメーションが終了した時のコールバックを指定できるので、そこでresolve()を指定している。
別の書き方.js
    $("#div1").hide(1000);
    var promise = $("#div1").promise();
    promise.done(onSuccess1);

進捗表示のサンプル

function doWork(){
    var defer = $.Deferred(),
    timer_id,
    percent = 0;

//1秒ごとにdefer.notify(percent);する
    timer_id = setInterval(function (){
    percent += 10;
    defer.notify(percent);

    if(percent >= 100){
    defer.resolve();
    clearInterval(timer_id);
    }
    },1000);
    return defer.promise();
}

var promise = doWork();

promise.done(function(){
    console.log("終わりました");
});


promise.progress(function (percent){
    console.log(percent + "%終了しました");
});

.then()

  • then()は、done()、fail()、progress()用のコールバック関数をまとめて登録できる
$.ajax({
    url:"ajax1.php"
})
.then(onSuccess,onFailure);

then()の使いどころ

AJAX1への通信が無事終了したら、AJAX2の通信を行い、終わったら、AJAX3との通信を行う。

$.get("ajax1.php")
.then(function(){
    return $.get("ajax2.php");
})
.then(function(){
    return $.get("ajax3.php");
})
.done(function (){
    console.log("終了");
});

メソッドチェーンを使わない書き方

var promise1 = $.get("ajax1.php");

var promise2 = promise1.then(function(){
    return $.get("ajax2.php");
});

var promise3 = promise2.then(function(){
    return $.get("ajax3.php");
});

var promise3.done(function(){
    console.log("終了");
});

スクリーンショット 2016-03-25 16.40.59.png

then()解説

  • ユーザーが作成するcallbackを内側に包み込むもっと大きなコールバック関数を作成する。それをpromiseに登録する。
  • ユーザーが作成したcallbackを実行する。
  • callbackから返ってきたpromiseが無事resolve()された時は新しいprimiseをresolve()する。
  • reject()された場合は、新しいpromiseをrejectする。

thenの第2引数にコールバック関数を指定した場合

スクリーンショット 2016-03-25 16.47.56.png

$.when()

  • 2つ以上のPromiseが成功(または失敗)したら、という条件で、コールバック関数をしたい場合
var promise1 = $.get("ajax1.php");
var promise2 = $.get("ajax2.php");

var promise = $.when(promise1,promise2);
promise.done(onSuccess);
promise.fail(onFailure);

1行で書く

$.when($.get("ajax1.php"), $.get("ajax2.php")).then(onSuccess,onFailure);

アニメーション

var promise1 = $.get("ajax1.php"),
promise2 = $("#sidebar").fadeOut(1500).promise();

$.when(promise1, promise2).done(function(){
    console.log("フェードアウトとAJAX完了");
});

$.Callbacks()

before.js
function myfunc1(){
    console.log("処理1");
}

function myfunc2(){
    console.log("処理2");
}


$("#box1").fadeIn(3000,function(){
    myfunc1();
    myfunc2();
})
after.js
var myCall = $.Callbacks(); //コールバックを管理する変数を定義

//オブジェクトに処理後に実行させたいコールバック関数を登録する
myCall.add(myfunc1);
myCall.add(myfunc2);

$("#box1").fadeIn(2000,function(){
    myCall.fire();
});

//$("#box1").fadeIn(2000,myCall.fire); と同じ