我有一个非常直截了当的问题,我在这里:
_.each()
。$q
版本。现在,我的问题是我希望在继续下一次迭代之前,每次迭代都要等待。
我的第一个版本是这个,直到我意识到我需要等待updateWidget()
完成:
_.each(widgets, function (wid) {
if (wid.dataModelOptions.linkedParentWidget) {
updateWidget(wid, parentWidgetData);
}
});

我的第二个版本就是这个版本,它会返回一个承诺。但是,当然,我仍然遇到迭代继续而不等待的问题:
_.each(widgets, function (wid) {
if (wid.dataModelOptions.linkedParentWidget) {
updateWidget(wid, parentWidgetData).then(function(data){
var i = 1;
});
}
});

和被调用的函数,它返回一个deferred.promise
对象(然后对小部件数据进行服务调用):
function updateWidget(widget, parWidData) {
var deferred = $q.defer();
// SAVE THIS WIDGET TO BE REFRESHED FOR THE then() SECTION BELOW
$rootScope.refreshingWidget = widget;
// .. SOME OTHER VAR INITIALIZATION HERE...
var url = gadgetDataService.prepareAggregationRequest(cubeVectors, aggrFunc, typeName, orderBy, numOrderBy, top, filterExpr, having, drillDown);
return gadgetDataService.sendAggGetRequest(url).then(function (data) {
var data = data.data[0];
var widget = {};
if ($rootScope.refreshingWidget) {
widget = $rootScope.refreshingWidget;
}
// BUILD KENDO CHART OPTIONS
var chartOptions = chartsOptionsService.buildKendoChartOptions(data, widget);
// create neOptions object, then use jquery extend()
var newOptions = {};
$.extend(newOptions, widget.dataModelOptions, chartOptions);
widget.dataModelOptions = newOptions;
deferred.resolve(data);
});
return deferred.promise;
}

我很感激您关于如何"暂停"在每次迭代时,并在被调用函数完成后继续。
谢谢你, 鲍勃*******更新************
我的最新版本的迭代代码包括$q.all()
,如下所示:
// CREATE ARRAY OF PROMISES !!
var promises = [];
_.each(widgets, function (wid) {
if (wid.dataModelOptions.linkedParentWidget) {
promises.push(updateWidget(wid, parentWidgetData));
}
});
$q.all(promises)
.then(function () {
$timeout(function () {
// without a brief timeout, not all Kendo charts will properly refresh.
$rootScope.$broadcast('childWidgetsRefreshed');
}, 100);
});

答案 0 :(得分:4)
最简单的是:
var queue = $q.when();
_.each(widgets, function (wid) {
queue = queue.then(function() {
if (wid.dataModelOptions.linkedParentWidget) {
return updateWidget(wid, parentWidgetData);
}
});
});
queue.then(function() {
// all completed sequentially
});
注意:最后,队列将使用最后一次迭代的返回值解析
如果您编写了许多这样的异步函数,将它包装到实用程序函数中可能会很有用:
function eachAsync(collection, cbAsync) {
var queue = $q.when();
_.each(collection, function(item, index) {
queue = queue.then(function() {
return cbAsync(item, index);
});
});
return queue;
}
// ...
eachAsync(widgets, function(wid) {
if (wid.dataModelOptions.linkedParentWidget) {
return updateWidget(wid, parentWidgetData);
}
}).then(function() {
// all widgets updated sequentially
// still resolved with the last iteration
});
这些函数在“预处理”阶段构建 promises链,因此您的回调会按顺序调用。还有其他方法可以做到这一点,其中一些方法效率更高,内存更少,但这个解决方案最简单。
此方法将隐藏最后一次迭代的返回值,并且不会在beforehands之前构建完整的promise链。缺点是,它只能用于像对象这样的数组。
function eachAsync(array, cbAsync) {
var index = 0;
function next() {
var current = index++;
if (current < array.length) {
return $q.when(cbAsync(array[current], current), next);
}
// else return undefined
}
// This will delay the first iteration as well, and will transform
// thrown synchronous errors of the first iteration to rejection.
return $q.when(null, next);
}
这将迭代任何可迭代的:
function eachAsync(iterable, cbAsync) {
var iterator = iterable[Symbol.iterator]();
function next() {
var iteration = iterator.next();
if (!iteration.done) {
// we do not know the index!
return $q.when(cbAsync(iteration.value), next);
} else {
// the .value of the last iteration treated as final
// return value
return iteration.value;
}
}
// This will delay the first iteration as well, and will transform
// thrown synchronous errors of the first iteration to rejection.
return $q.when(null, next);
}
请记住,当集合在迭代期间发生更改时,这些方法的行为会有所不同。 promise链接方法基本上在集合开始迭代时构建集合的快照(各个值存储在链式回调函数的闭包中),而后者则没有。
答案 1 :(得分:1)
我没有尝试解析_.each()中的每个promise,而是在_.each中构建一个promises数组来获取类似的数组:
promises = [gadgetDataService.sendAggGetRequest(url1), gadgetDataService.sendAggGetRequest(url2)....]
然后立即解决所有问题,遍历结果并设置模型:
$q.all(promises).then(function(results){ // iterate through results here })