AJAX処理を順番に実行する

やりたいこと

複数のAJAX処理を一つずつ順番に、前の処理が終わるのを待って実行したい。

環境

jQuery 1.8 以降

やり方

jQueryのDeferredオブジェクトを利用してAJAX実行Queueを作成する。途中でエラーが発生した際にそのまま続行するQueueと以降の処理をキャンセルするQueue、2通り作ってみた。

エラー後も続行するQueue

// AJAX実行Queue
var ajaxQueue = function () {
    var previous = new $.Deferred().resolve();

    return function (fn) {
        // then()の第1と第2引数に同じ関数を渡す
        return previous = previous.then(fn, fn);
    };
}();

// キューが空なので即実行される
ajaxQueue(function () {
    return $.get('/first');
});

// 1つ目の処理が終わったら実行される
ajaxQueue(function() {
    return $.get('/second');
});

エラー後はキャンセルするQueue

この場合、一度エラーが発生すると以降常にキャンセルされ続けてしまうため、再び処理を開始するための初期化関数も用意した。

// AJAX実行Queue
var ajaxQueue = function () {
    var previous = new $.Deferred().resolve();

    return {
        put: function (fn) {
            // then()の第1引数のみ渡す
            return previous = previous.then(fn);
        },
        init: function () {
            // Deferredオブジェクトの初期化
            previous = new $.Deferred().resolve();
        }
    };
}();

// キューが空なので即実行される
ajaxQueue.put(function () {
    return $.get('/first');
});

// 1つ目の処理でエラーが発生していなければ実行される
ajaxQueue.put(function() {
    return $.get('/second');
});

// 初期化
ajaxQueue.init();

補足

AJAX処理に.done().fail()が登録されている場合、それらの実行まで完了してから次の処理が開始される。

おまけ

前の処理が終わっていないときは次の処理を阻止したい、という場合。

var ajaxQueue = function () {
    var previous = new $.Deferred().resolve();

    return function (fn) {
        if (previous.state() == 'pending') {
            alert('通信中です。しばらくお待ち下さい。');
            return;
        }
        
        return previous = previous.then(fn, fn);
    };
}();

参考

stackoverflow.com