Deferreds and Promises的新手。
这是我的[简化]代码,它在JavaScript对象中定义:
myFunction: function(d, cb)
{
return $.ajax('/myURL', {
contentType: 'application/json',
data: d,
dataType: 'json',
type: 'POST'
}).then(cb, cb);
},
flush: function(myArray)
{
return myFunction(myArray, myCallback);
}
以上工作正常。我可以调用flush(someArray),一段时间后我得到了ajax请求的结果。
问题:
我想修改flush函数,以便它首先将数组分成块(即较小的数组),然后在每个块上调用myFunction。然后,它必须一次性返回每个ajax调用中的 聚合 数据(最好是在数组中)。
我开始沿着以下几行修改flush(),但我知道它不太正确。有人可以为我填补/填补空白,或建议一个可以很好运作的重组吗?
感谢。
flush: function(myArray)
{
var chunk = 2;
var i, a;
var j = myArray.length;
var myArrayChunks = [];
for (i=0; i<j; i+=chunk)
{
a = myArray.slice(i, i+chunk);
myArrayChunks.push(a);
}
var myDeferreds = [];
for (i=0; i<myArrayChunks.length; i++)
{
// Here, I need to create a deferred object that will run: myFunction(myArrayChunks[i], myCallback)
// How do I do that?
var f = // The deferred object that will run: myFunction(myArrayChunks[i], myCallback)
myDeferreds.push(f);
}
return $.when.apply($, myDeferreds).then(function(){
// Here, I need to get the aggregated data that is returned by each of the deferreds. How do I do that?
console.log("FLUSH COMPLETE!");
});
}
答案 0 :(得分:0)
我下面粘贴的async
库允许您运行一系列异步/延迟请求,并将每个异步函数的结果传递给最终回调,该回调汇总了一组结果
特别是,请查看parallel
方法,该方法将同时执行所有异步请求,但无法保证它们将以何种顺序运行。如果您担心执行异步请求的顺序,查看series
和eachSeries
方法。
<强>平行强>
https://github.com/caolan/async#parallel
series / eachSeries:
https://github.com/caolan/async#seriestasks-callback
两种方法都会将结果聚合到最终结果对象中,该对象包含从您进行的每个异步调用传递的所有结果。
注意,要使用jQuery的延迟功能,您需要在&#34; final&#34;中调用.resolve()
。回调async.parallel
或async.each
或async.eachSeries
方法
以下是parallel
方法的示例:
async.parallel([
function(callback){
// some request
$.ajax(/*details*/, function(data) {
callback(null, data);
});
},
function(callback){
// some request
$.ajax(/*details*/, function(data) {
callback(null, data);
});
}
],
// "final" callback, invoked after all above functions have
// called their respective callback() functions
function(err, results){
if(err) {
// handle error
} else {
// results contains aggregated results from all
// async calls (2nd parameter in callback(errorParam, resultsParam)
console.log('all async methods finished!', results);
}
});
&#13;
这是一种传递数组并为每个数组元素生成异步方法的方法。 注意,async.each
方法中的每个异步调用必须在解析异步请求时调用callback()
,或者如果出现错误则在异步错误方法中调用callback(err)
。如果您将 N 元素数组传递给async.each
方法,则当所有 N 异步解析callback()
方法具有所有 N 时,将调用最终回调被援引。
async.each(array, function(element, callback) {
$.ajax(/* details */, {data: element}, function(data) {
// call `callback` when you're finished up
callback();
});
},
// "final" callback, invoked after each async call is resolved and
// invokes the callback() function
function(err){
if( err ) {
// handle errors
} else {
console.log('All async methods flushed!');
}
});
&#13;
我喜欢这个图书馆,一旦你开始使用它,它就会改变你的生活:]。祝你好运!
答案 1 :(得分:0)
由于你已经从ajax函数返回了一个promise,我建议你使用promises而不是普通的回调。这是一种方法:
myFunction: function(d) {
return $.ajax('/myURL', {
contentType: 'application/json',
data: d,
dataType: 'json',
type: 'POST'
});
},
flush: function(myArray, chunkSize) {
chunkSize = chunkSize || 2;
var index = 0;
var results = [];
var self = this;
return jQuery.Deferred(function(def) {
function next() {
var start = index;
var arrayChunk, promises = [];
index += chunkSize;
if (index < myArray.length) {
arrayChunk = myArray.slice(start, chunkSize);
// create chunkSize array of promises
arrayChunk.forEach(function(item) {
promises.push(self.myFunction(item));
});
$.when.apply($, promises).then(function() {
// results are in arguments[0][0], arguments[1][0], etc...
for (var i = 0; i < arguments.length; i++) {
results.push(arguments[i][0]);
}
// next iteration
next();
}, def.reject)
} else {
def.resolve(results);
}
}
// start first iteration
next();
}).promise();
}
obj.flush(myArray).then(function(results) {
// array of results here
}, function(jqXHR, textStatus, errorThrown) {
// error here
});
答案 2 :(得分:0)
通过创建http://stevegaines.info/api/Exams?id=3&extra=0
http://stevegaines.info/api/Exams/4
http://stevegaines.info/api/values
$http.get(url)
.then(function (dataResponse)
{
$scope.Exams = dataResponse.data;
}, function (error)
{
alert("error.statusText = " + error.statusText);
});
版本的$.ajax()
来实现此目的,我称之为$.ajaxChunk()
,它会获取一系列数据并为您完成分块。
// Send ajax calls in chunks from an array with no more than X in flight at the same time
// Pass in array of data where each item in dataArray is sent separately
// in an ajax call
// Pass settings.chunkSize to specify the chunk size, defaults to 2 if not present
// Returns a promise
// The resolved value of promise is an array of results
// The rejected value of the promise is whatever jQuery result failed first
$.ajaxChunk = function(dataArray, url, settings) {
settings = settings || {};
var chunkSize = settings.chunkSize || 2;
var index = 0;
var results = [];
return jQuery.Deferred(function(def) {
function next() {
var start = index;
var arrayChunk, promises = [];
index += chunkSize;
if (index < myArray.length) {
arrayChunk = myArray.slice(start, chunkSize);
// create chunkSize array of promises
arrayChunk.forEach(function(item) {
// make unique copy of settings object for each ajax call
var localSettings = $.extend({}, settings);
localSettings.data = item;
promises.push($.ajax(url, localSettings));
});
$.when.apply($, promises).then(function() {
// results are in arguments[0][0], arguments[1][0], etc...
for (var i = 0; i < arguments.length; i++) {
results.push(arguments[i][0]);
}
next();
}, def.reject)
} else {
def.resolve(results);
}
}
// start first iteration
next();
}).promise();
}
并且,样本用法:
$.ajaxChunk(arrayOfData, '/myURL', {
contentType: 'application/json',
dataType: 'json',
type: 'POST',
chunksize: 2
}).then(function(results) {
// array of results here
}, function(jqXHR, textStatus, errorThrown) {
// error here
})
如果这里真正的要求是您不能同时处理超过X ajax的呼叫,那么就会有更高效,更快速(端到端时间)的方式比分块。相反,你要跟踪&#34;在飞行中的确切数量ajax调用&#34;在任何时候,一旦完成,你就开始下一个。这比你发送整个块的块的效率要高一些,然后等待整个块完成。我编写了一个实现这个的jQuery助手:
$.ajaxAll = function(dataArray, url, settings, maxInFlight) {
maxInFlight = maxInFlight || 1;
var results = new Array(dataArray.length);
settings = settings || {};
var index = 0;
var inFlight = 0;
return jQuery.Deferred(function(def) {
function runMore() {
while (inFlight < maxInFlight && index < dataArray.length) {
(function(i) {
var localSettings = $.extend({}, settings);
localSettings.data = dataArray[index++];
++inFlight;
$.ajax(url, localSettings).then(function(data, textStatus, jqXHR) {
--inFlight;
results[i] = data;
runMore();
}, def.reject);
})(index);
}
// if we are all done here
if (inFlight === 0 && index >= dataArray.length) {
def.resolve(results);
}
}
// start first iteration
runMore();
}).promise();
}
注意:如果为1
参数传递maxInFlight
,则会依次运行串联的ajax调用。结果总是按顺序返回。
并且,样本用法:
$.ajaxAll(arrayOfData, '/myURL', {
contentType: 'application/json',
dataType: 'json',
type: 'POST'
}, 2).then(function(results) {
// array of results here
}, function(jqXHR, textStatus, errorThrown) {
// error here
})
答案 3 :(得分:0)
感谢所有人的好建议。
我在我的解决方案中使用了建议技术的组合。
关键是要创建一个promises数组,然后将所需的调用(每个都有自己的数组块作为参数传递给它)发送到发出ajax请求的函数。我之前没有意识到的一件事就是在那个时刻调用了ajaxCall()函数,这很好,因为它返回了一个推送到数组上的promise。
在此之后,&#39; when.apply&#39; line在等待所有ajax承诺完成之前就可以了。然后&#39;然后&#39;函数用于整理所需的所有结果(显然,确切的机制取决于返回的参数的格式)。然后将结果发送到theResultsHandler(),它取代了我在问题中首次发布的代码中的原始回调。
希望这对其他Promise-novices有用!
ajax调用函数是:
ajaxCall: function(d) {
return $.ajax('/myURL', {
contentType: 'application/json',
data: d,
dataType: 'json',
type: 'POST'
});
},
在flush()函数内......
var promises = [];
var i, j;
for (i=0; i<batchChunks.length; i++)
{
promises.push(self.ajaxCall(batchChunks[i]));
}
var results = [];
return $.when.apply($, promises).then(function(){
console.log("arguments = " + JSON.stringify(arguments));
for (i = 0; i < arguments.length; i++)
{
for (j = 0; j < arguments[i][0].length; j++)
{
results.push(arguments[i][0][j]);
}
}
return self.theResultsHandler(results);
});