通过四个异步调用收集数据到对象,并立即处理对象

Collect data to object with four async calls and handle the object onready

本文关键字:对象 数据 处理 调用 异步 四个      更新时间:2023-09-26

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

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,这需要四种数据(extraData, colorData, sizeData &weightData)和我有三个对象:App, Utils &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.parseResponseApp.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()的文档和围绕这一点的讨论并没有帮助我。因此,我将非常高兴并感谢任何帮助或建议。

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

我想你要找的是承诺/延迟。

对于承诺,你可以这样写:

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只是简单的计算参数的个数,如果所有的promise都被解析了,它会调用then来计算promise的结果。

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

对于这种情况,我的建议是这样的。编写如下函数

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

,其中completed是您必须接收的正面回调数。一旦每个函数都收到回调,就可以增加"completed"计数器并调用checkHandler函数。这样就完成了!

在示例

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