使用四个异步调用将数据收集到对象,并在onready上处理该对象

时间:2013-03-29 13:09:54

标签: javascript performance jquery-deferred

我有一个处理程序(回调),一个要处理的对象和四个函数,它们将数据收集到对象。在我的情况下,我希望异步调用四个数据检索器,当完成所有四个的执行时,处理结果对象(类似于以下内容):

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 );

当然,此代码无法正常运行。如果我链接数据检索功能,它们将被一个接一个地调用,对吧? 所有四个函数都应该异步调用,因为它们被执行的时间太长而无法逐个调用它们。

更新

感谢大家的建议!我更喜欢$.Deferred(),但我觉得让它按照我需要的方式工作有点困难。我需要的是异步制作view,这需要四种数据(extraDatacolorDatasizeData& weightData)我有三种对象:AppUtils& Tools

只是一个小描述:view是通过调用App.getStuff传递App.handleStuff作为回调来创建的。 App.getStuff正文中的回调仅被称为$.when(App.getExtraData(), App.getColorData(), App.getSizeData(), App.getWeightData())。之前Utils.asyncRequest传递Tools.parseResponse作为回调被调用。

那么,现在问题是我应该在每个App.get*Data()内创建四个延迟对象,还要从每个return deferred.promise()创建deferred.resolve()? 我应该在订单的最后一个函数中Tools.parseResponse(在我的示例中为App.getExtraData 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 ); )吗?

jQuery.Deferred()

我没想到上面示例中的代码可以正常工作,它仅用于说明目的。

我一直试图解决这个问题很长一段时间,但仍然没有结果。不幸的是,{{1}}的文档和围绕此问题的讨论对我没有帮助。所以,我会非常高兴和乐于助人或建议。

3 个答案:

答案 0 :(得分:0)

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

有了承诺,你可以写下这样的东西:

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有一个OK实现:http://api.jquery.com/jQuery.when/

答案 1 :(得分:0)

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

答案 2 :(得分:0)

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

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

已完成的是您必须收到的正回调数。 只要每个函数都收到回调,您就可以递增“completed”计数器并调用checkHandler函数。你已经完成了!

示例中的

function getColorData() {
   $.get('ajax/test.html', function(data) {
      completed++;
      checkHandler();
   });
}