Ajax非同期処理を実装

2017/05/11

JavaScriptでAPIからデータ取得・処理する際、ネスト地獄で複雑なコードになりがち。 かと言って、AngularやReactなどのフレームワークを使うと勉強コスト、スパゲティー設計など本末転倒な結果になりやすい。

フレームワークの最大のデメリットは、

中で何が行われているか?ソースを解読しないとわからない

と言うことで、こみいった実装をせずシンプルに実装してみる。

(1) APIリクエストの配列設定 (2) Ajax処理の抽象化 (3) 並列処理の抽象化 (4) コールバック処理の考慮


    $(document).on('click', '.action-api', function() {
        //API設定(抽象化する必要あり)
        var requests = [
            {
                url: 'https://xxxx/api/user',
                params: {'user_id': 394},
                callback: callbackUser
            },
            {
                url: 'https://xxxx/api/order',
                params: {'user_id': 394, 'item_id': 31},
                callback: callbackApplication
            },
        ];

        //並列処理実行
        parallelAjax(requests, doneCallback);

        //各APIリクエストのコールバック
        function callbackUser(results) {
            console.log(results);
        }
        function callbackApplication(results) {
            console.log(results);
        }
        //並列処理完了後のコールバック
        function doneCallback(results) {
            console.log(results);
        }
    });

var requestAjax = function(values){
    var $ajax = $.ajax(values);
    var defer = new $.Deferred();
    $ajax.done(function(data, status, $ajax){
        defer.resolveWith(this, arguments);
    });
    $ajax.fail(function(data, status, $ajax){
        defer.resolveWith(this, arguments);
    });
    return $.extend({}, $ajax, defer.promise());
};

function parallelAjax(requests, callback) {
    var results = [];
    $.each (requests, function(index, value) {
        var $ajax = requestAjax({url: value.url, data: value.params}).done(function(res, status) {
            if (value.callback) {
                value.callback(res);
            }
        });
        results.push($ajax);
    });
    $.when.apply(null, results).done(function(){
        if (callback) callback(results);
    });
    $.when.apply(null, results).fail(function(){
    });
}

APIリクエストの配列設定

並列処理は後々ループで実行ため、オブジェクト配列で設定しておく。 差し当たり以下の項目で設定 ・URL ・URLパラメータ ・API処理後のコールバック (その他、POST/GETやデータ型なども設定できると良い?)


        var requests = [
            {
                url: 'https://xxxx/api/user',
                params: {'user_id': 394},
                callback: callbackUser
            },
            {
                url: 'https://xxxx/api/application',
                params: {'user_id': 394},
                callback: callbackApplication
            },
        ];

こうすることで、callbackを別モデル、ファイルなどに分離して記述できるかと。 実用レベルだと、APIリクエスト設定も動的に抽象化が必要ですが。。。

Ajax処理の一般化

並列処理をする際「jQuery.Deferred」を利用 ざっとした流れは、 (1) Deferredオブジェクトを作成 (2) Ajaxリクエスト (3) Ajax処理後返り値を Deferred.resolveWith() でコールバック

詳しくは、 ・「爆速でわかるjQuery.Deferred超入門」「結局jQuery.Deferredの何が嬉しいのか分からない、という人向けの小話」を参照


var requestAjax = function(values) {
    var $ajax = $.ajax(values);
    var defer = new $.Deferred();
    $ajax.done(function(data, status, $ajax) {
        defer.resolveWith(this, arguments);
    });
    $ajax.fail(function(data, status, $ajax) {
        defer.resolveWith(this, arguments);
    });
    return $.extend({}, $ajax, defer.promise());
};

並列処理の一般化

(1) 配列化したリクエストをループで処理 (2) Ajax実行 (3) APIリクエストで設定したコールバックを実行 (3) $.whenで並列処理完了後の処理


function parallelAjax(requests, callback) {
    var results = [];
    $.each (requests, function(index, value) {
        var $ajax = requestAjax({url: value.url, data: value.params}).done(function(res, status) {
            if (value.callback) {
                value.callback(res);
            }
        });
        results.push($ajax);
    });
    $.when.apply(null, results).done(function(){
        if (callback) callback(results);
    });
    $.when.apply(null, results).fail(function(){
    });
}