如何产生结果 Javascript 嵌套延迟

Posted

技术标签:

【中文标题】如何产生结果 Javascript 嵌套延迟【英文标题】:How to Yield Results Javascript Nested Deferreds 【发布时间】:2013-12-17 23:59:38 【问题描述】:

我正在使用 ESRI javascript API 检索 ArcGIS Server 数据集中的所有记录以进行客户端处理。服务器将每个响应限制为 1000 条记录。这意味着我必须在检索到我的特征时跟踪它们,然后检索下一批。对检索记录的 API 的调用返回一个dojo/Deferred 对象。

我希望能够检索一批 1000 条记录,对其进行处理,然后按顺序将它们保存回数据集。同时,一旦从数据集中检索到一批记录,就会开始检索下一批记录。

我使用递归函数调用完成了类似的操作,并将生成的dojo/Deferred 保存到列表中,以便稍后使用dojo/promise/all 处理。但是,这意味着在检索到所有要素后立即处理所有要素。我宁愿能够在检索到每个批次时单独处理它们。

我的应用程序使用 dojo 与 ESRI API 和 jQuery/jQuery Mobile。

这是我一次返回所有功能的代码:

//layer = dataset (geographic data)
//count = count of records (features) in dataset
//objectIds = list of all unique record ID's in dataset.  This can be retrieved from the server and is not limited by the 1000 record limit
//Query = ESRI API Query Task used to retrieve features from the dataset

if (count > layer.maxRecordCount) 

    var features = [];

    var i = 0;

    var deferreds = [];
    for (i; i < objectIds.length; i += layer.maxRecordCount) 

        var q = new Query();
        q.objectIds = objectIds.slice(i, i + layer.maxRecordCount);

        var deferred;
        if (select)  deferred = layer.selectFeatures(q, selectionType); 
        else  deferred = layer.queryFeatures(q); 

        deferreds.push(deferred);

    

    var deferred = all(deferreds).then(function(featuresets) 

        var featureLists = array.map(featuresets, function(featureset) 
            return featureset.features || featureset;
        );

        var features = [].concat.apply([], featureLists);

        return features;

    );

    return deferred;


更新:

我已经找到了一种方法来使用Array 作为queue 来完成我想要的事情。

这是从数据库中检索记录的函数:

getAllFeatures : function(layer, returnGeometry, fields) 

    var queue = ["start"];

    var q = new esriQuery();
    q.where = "1=1";

    var qt = new QueryTask(layer.url);

    layer.queryIds(q).then(function(objectIds) 

        var deferreds = [];

        for (var i = 0; i < objectIds.length; i += layer.maxRecordCount) 

            var q = new esriQuery();
            q.objectIds = objectIds.slice(i, i + layer.maxRecordCount);
            q.returnGeometry = !!returnGeometry;
            q.outFields = fields && [layer.objectIdField].concat(fields) || ["*"];

            deferreds.push(qt.execute(q).then(function(featureSet) 
                queue.push(featureSet.features);
            ));

        

        all(deferreds).then(function() 
            queue.push("stop");
        );

    );

    return queue;


这是处理数据的代码:

var queue = pgUtils.getAllFeatures(layer, false, [priorityField.name]);

var features = queue.shift();

var interval;

if (features === "start") 

    interval = setInterval(function() 
        features = queue.shift();
        if (features && features instanceof Array) 
            self._prioritize(features, formData);
            new esriRequest(
                url : layer.url + "/applyEdits",
                content : 
                    f : "json",
                    updates : JSON.stringify(features)
                
            , usePost : true);
         else if (features === "stop") 
            clearInterval(interval);
        
    , 500);

如您所见,我使用名为 queueArraygetAllFeatures 函数中推送单个响应,并使用 setIntervalqueue 检索这些响应,直到找到 "stop" 信号.到目前为止,这似乎适用于我的 450 条记录的测试数据集。我不确定这将如何适用于更大的数据集。我绝对愿意接受任何关于更好方法的建议。

【问题讨论】:

【参考方案1】:

查看 DeferredList。

var def_array = [];
for(..) 
  var def = new Deferred();
   ...
  def_array.push(def);

new DeferredList(def_array).then(function(res)
   ...
   //this runs only all the deferreds in the def_array is invoked and completed
);

DeferredList 有许多其他参数/​​标志,用于特定目的,根据要求。但是,对于您的情况,我想,上述解决方案就足够了。

【讨论】:

感谢您的建议。在 dojo 1.9 中,DeferredList 已弃用。相反,他们建议使用dojo/promise/all,这是我在上面发布的代码中使用的。不幸的是,无论我使用all 还是DeferredList,都意味着要等到所有批次都完成后再完成处理。我正在尝试独立于其他批次进行一次批量处理。【参考方案2】:

如果我对您的问题的解释正确,那么您基本上希望以串行方式而不是并行方式请求批次,在请求下一个之前处理每个批次。正如您所指出的,all 确实适用于并行处理。你需要一种不同的方法来做你想做的事(注意我没有办法对此进行测试,所以它可能仍然需要一些工作):

var i = 0,
    len = objectIds.length,
    features = [];

function requestNext() 
    var q = new Query(),
        promise;

    q.objectIds = objectIds.slice(i, i + layer.maxRecordCount);
    promise = select ? layer.selectFeatures(q, selectionType) :
        layer.queryFeatures(q);

    return promise.then(function (featureset) 
        // Add the latest set of results to the features array
        features = features.concat(featureset.features || featureset);

        // If there are more objects to query, call this function again,
        // chaining the subsequent request's resolution to this promise;
        // otherwise, return the built features array
        i += layer.maxRecordCount;
        return i < len ? requestNext() : features;
    );


return requestNext();

【讨论】:

我实际上是在尝试并行执行所有操作。目前,我发布的函数向服务器提交了多个Query 请求,然后等待所有响应,然后使用all 返回任何功能。我正在寻找一个并行发送请求并并行返回响应的函数。

以上是关于如何产生结果 Javascript 嵌套延迟的主要内容,如果未能解决你的问题,请参考以下文章

如何在javascript中过滤数组内的嵌套对象

JavaScript闭包

延迟合并处理任务

javascript 多层嵌套try catch问题

javascript 将嵌套列表与prev结果合并

休眠从对象中延迟获取嵌套列表