14

.start()私は、プロトタイプが引数として2つのコールバックを取るメソッドで拡張された標準のjavascriptオブジェクトを持ってsuccessいます:failureそれぞれ。このメソッドは非同期処理 (AJAX ではありません) を実行し、この処理の結果に応じて、成功または失敗のコールバックを呼び出します。

これを図式化する方法は次のとおりです。

function MyObject() {
}

MyObject.prototype.start = function(successCallback, errorCallback) {
    (function(s, e) {
        window.setTimeout(function() {
            if (Math.random() < 0.8) {
                s();    
            } else {
                e();    
            }
        }, 2000);    
    })(successCallback, errorCallback);
}

メソッド内で実行される正確な処理はそれほど重要ではなく、非同期で非ブロッキングであることだけが重要です。start メソッドが処理を終了する時点を制御することはできません。また、このメソッドのプロトタイプと実装を制御することもできません。

私が制御できるのは、successおよびfailureコールバックです。それらを提供するのは私次第です。

これで、これらのオブジェクトの配列ができました:

var arr = [ new MyObject(), new MyObject(), new MyObject() ];

この配列の要素の順序は重要です。配列の各要素でメソッドを連続してトリガーする必要がありますが.start()、前の要素が完了した (つまり、成功のコールバックが呼び出された) 場合のみです。エラーが発生した場合 (失敗コールバックが呼び出された場合)、実行を停止し、配列の残りの要素に対して .start メソッドを呼び出さないようにします。

再帰関数を使用して、これを単純に実装できます。

function doProcessing(array, index) {
    array[index++].start(function() {
        console.log('finished processing the ' + index + ' element');
        if (index < array.length) {
            doProcessing(array, index);
        }
    }, function() {
        console.log('some error ocurred');
    });
}

doProcessing(arr, 0);

これは問題なく動作しますが、jQuery 1.5 で導入されたjQuery の deferred Objectを見ると、このコードには改善の余地があると思います。残念ながら、私はまだそれに慣れていません。私はそれを学ぼうとしています。

私の素朴なコードを適応させて、この新しい API を利用することは可能ですか?

これが私の実装のjsfiddleです。

4

3 に答える 3

4

次のようなことができます: ( jsFiddle )

function MyObject() {
}

MyObject.prototype.start = function(queue) {
    var deferred = $.Deferred();
    //only execute this when everything else in the queue has finished and succeeded
    $.when.apply(jQuery,queue).done(function() { 
        window.setTimeout(function() {
            if (Math.random() < 0.8) {
                deferred.resolve();    
            } else {
                deferred.reject();    
            }
        }, 2000); 
    });
    return deferred;
}

var arr = [ new MyObject(), new MyObject(), new MyObject() ];

var queue = new Array();
$.each(arr, function(index, value) {
    queue.push(value.start(queue)
        .done(function() {
           console.log('succeeded ' + index);
        })
        .fail(function() {
           console.log('failed ' + index);
        }));
});

ただし、これを改善と見なすかどうかはよくわかりません。

于 2011-10-12T18:11:46.043 に答える
3

プログラミングをするとき、GRASP の原則やガイドラインを覚えておくことは非常に重要です。

http://en.wikipedia.org/wiki/GRASP_(オブジェクト指向デザイン)

凝集度が高く結合度が低いということは、コードがより良くなり、再利用可能になり、保守が容易になることを意味します。

したがって、クラス MyObject はキューの存在を認識してはなりません。MyObject は、独自の機能やメソッドなどを認識します。

// Class MyObject

function MyObject(name) {
    this.name = name;
}

MyObject.prototype.start = function() {

    var deferred = $.Deferred();
    var self = this;
    setTimeout(function() {
        if (Math.random() <= 0.8) {
            console.log(self.name + "... ok");
            deferred.resolve();
        } else {
            console.log(self.name + "... fail");
            deferred.reject();
        }
    }, 1000);

    return deferred.promise();
} 

main/caller 関数は MyObject の存在を認識し、それらが順番に実行される 3 つのインスタンスを作成します。

// Create array of instances
var objectArray = [ new MyObject("A"), new MyObject("B"), new MyObject("C") ];

// Create array of functions to call start function
var functionArray = [];
$.each(objectArray, function(i, obj) {
    functionArray.push(
        function() {
           return obj.start();
        }
    );
});

// Chain three start calls 
$.iterativeWhen(functionArray[0], functionArray[1], functionArray[2])
.done(function() {

    console.log("First: Global success");

    // Chain three start calls using array
    $.iterativeWhen.apply($, functionArray)
    .done(function() {
        console.log("Second: Global success");
    })
    .fail(function() {
        console.log("Second: Global fail");
    });

})
.fail(function() {
    console.log("First: Global fail");
});

jQuery 用のプラグインを作成しました: iterativeWhen. jQuery 1.8 以降のバージョンで動作します。

$.iterativeWhen = function () {

    var deferred = $.Deferred();
    var promise = deferred.promise();

    $.each(arguments, function(i, obj) {

        promise = promise.then(function() {
            return obj();
        });
    });

    deferred.resolve();

    return promise;
}; 

Jsfiddle はこちら: http://jsfiddle.net/WMBfv/

于 2013-07-13T11:14:32.417 に答える
2

実装に問題はありません。誰もが知っているように、jQuery を使用することが常に最善の方法であるとは限りません。

私は次のようにします: ( MyObject クラスを変更する必要はありません..)

function doProcessing(array, index) {
    var defer = new $.Deferred();

    $.when(defer).then(doProcessing);

    array[index++].start(function() {
        log('finished processing the ' + index + ' element');
        if (index < array.length) {
            defer.resolve(array, index);
        }
    }, function() {
        log('some error ocurred => interrupting the process');
    });
};

ご覧のとおり、プレーンな JavaScript メソッドに勝る利点はありません。:)

これが私のフィドルです:http://jsfiddle.net/jwa91/EbWDQ/

于 2011-10-12T18:33:33.760 に答える