0

I have a handler (callback), an object to handle and four functions, which collect the data to object. In my case I wish to asynchronously call four data retrievers and when execution of all four is complete, handle the resulting object (something similar to the following):

var data = {};

function handle (jsObj) {}

// data retrieving
function getColorData () {}
function getSizeData () {}
function getWeightData () {}
function getExtraData () {}

data.color = getColorData();
data.size = getSizeData();
data.weight = getWeightData();
data.extra = getExtraData();

handle( data );

Of course, this code will not work properly. And if I chain data retrieving functions, they will be called one after another, right? All four functions should be called asynchronously, cause they are being executed for too long to call them one by one.

Updated:

Thanks to everybody for your suggestions! I prefered $.Deferred(), but I found it slightly difficult to make it work the way I need. What I need is to asynchronously make a view, which requires four kinds of data (extraData, colorData, sizeData & weightData) and I have three objects: App, Utils & Tools.

Just a small description: view is created by calling App.getStuff passed App.handleStuff as a callback. Callback in the body of App.getStuff is called only $.when(App.getExtraData(), App.getColorData(), App.getSizeData(), App.getWeightData()). Before that Utils.asyncRequest passed Tools.parseResponse as a callback is called.

So, now the question is should I create four deferred objects inside each App.get*Data() and also return deferred.promise() from each of them? And should I deferred.resolve() in the last function in my order (Tools.parseResponse for App.getExtraData in my example)?

var view,
    App,
    Utils = {},
    Tools = {};

// Utils
Utils.asyncRequest = function (path, callback) {
    var data,
        parseResponse = callback;

    // do something with 'data'

    parseResponse( data );
};

// Tools
Tools.parseResponse = function (data) {
    var output = {};

    // do something to make 'output' from 'data'

    /* So, should the deferred.resolve() be done here? */
    deferred.resolve(output);
    /// OR   deferred.resolve();
    /// OR   return output;
};

// App
App = {
    // Only one method really works in my example
    getExtraData : function () {
        var deferred = new jQuery.Deferred();

        Utils.asyncRequest("/dir/data.txt", Tools.parseResponse);

        return deferred.promise();
    },
    // Others do nothing
    getColorData  : function () { /* ... */ },
    getSizeData   : function () { /* ... */ },
    getWeightData : function () { /* ... */ }
};
App.getStuff = function (callback) {
    $.when( 
        App.getExtraData(), 
        App.getColorData(), 
        App.getSizeData(), 
        App.getWeightData()
    )
     .then(function (extraData, colorData, sizeData, weightData) {
        var context,
            handleStuff = callback;

        // do something to make all kinds of data become a single object

        handleStuff( context );
    });
};
App.handleStuff = function (stuff) { /* ... */ };

/// RUN
view = App.getStuff( App.handleStuff );

I did not expect the code in my example above to work, it is for illustrative purposes.

I've been trying to solve this for quiet a long time and it still gives no result. The documentation for jQuery.Deferred() and discussions around this, unfortunately, did not help me. So, I would be very glad and greatful for any help or advise.

4

3 回答 3

0

从概念上讲,您将使用一个随着每次异步调用完成而递增的计数器。在计数器被所有异步调用递增后,主调用者​​应该继续。

于 2013-03-29T13:16:07.570 回答
0

我可以为这种情况提出的建议是这样的。写一个这样的函数

var completed = 0;
checkHandler = function() {
  if(completed == 4) {
    handle(data);
  }
}

其中 completed 是您必须收到的肯定回调的数量。一旦每个函数收到回调,您就可以增加“完成”计数器并调用 checkHandler 函数。你就完成了!

例如

function getColorData() {
   $.get('ajax/test.html', function(data) {
      completed++;
      checkHandler();
   });
}
于 2013-03-29T13:18:33.947 回答
0

我认为您正在寻找的是Promises / Deferreds。

使用 Promise,您可以编写如下内容:

when(getColorData(), getSizeData(), getWeightData(), getExtraData()).then(
    function (colorData, sizeData, weightData, extraData) {
        handle(/*..*/);
    }
)

当异步调用完成时,这些get*Data()函数将返回一个它们履行的承诺。

前任:

function getData() {
    var promise = new Promise();
    doAjax("getData", { "foo": "bar" }, function (result) {
        promise.resolve(result);
    });
    return promise;
}

简单地计算参数的when数量,如果它的所有承诺都已解决,它将then使用承诺的结果进行调用。

jQuery 有一个好的实现:http ://api.jquery.com/jQuery.when/

于 2013-03-29T13:14:57.727 回答