javascript - 如何在 for 循环(每次迭代都会生成一个 promise)完成后返回单个 promise?
我的 Promise 返回代码有问题,我有一个函数 getTagQuotes,它包含一个 for 循环,该循环可以多次调用 API 将数据返回到数组中。
我的这段代码如下开始:
// If there are tags, then wait for promise here:
if (tags.length > 0) {
// Setting promise var to getTagQuotes:
var promise = getTagQuotes(tags).then(function() {
console.log('promise =',promise);
// This array should contain 1-3 tags:
console.log('tweetArrayObjsContainer =',tweetArrayObjsContainer);
// Loop through to push array objects into chartObj:
for (var i=0; i<tweetArrayObjsContainer.length; i++) {
chartObj.chartData.push(tweetArrayObjsContainer[i]);
}
// Finally draw the chart:
chartDirective = ScopeFactory.getScope('chart');
chartDirective.nvd3.drawChart(chartObj.chartData);
});
}
我带有 promise 返回的 getTagQuotes 函数:
function getTagQuotes(tags) {
var deferred = $q.defer(); // setting the defer
var url = 'app/api/social/twitter/volume/';
// My for loop, which only returns ONCE, even if there are 3 tags
for (var i=0; i<tags.length; i++) {
var loopStep = i;
rawTagData = [];
// The return statement
return GetTweetVolFactory.returnTweetVol(url+tags[i].term_id)
.success(function(data, status, headers, config) {
rawTagData.push(data);
// One the last loop, call formatTagData
// which fills the tweetArrayObjsContainer Array
if (loopStep === (rawTagData.length - 1)) {
formatTagData(rawTagData);
deferred.resolve();
return deferred.promise;
}
});
}
function formatTagData(rawData) {
for (var i=0; i<rawData.length; i++) {
var data_array = [];
var loopNum = i;
for (var j=0; j<rawData[loopNum].frequency_counts.length; j++) {
var data_obj = {};
data_obj.x = rawData[loopNum].frequency_counts[j].start_epoch;
data_obj.y = rawData[loopNum].frequency_counts[j].tweets;
data_array.push(data_obj);
}
var tweetArrayObj = {
"key" : "Quantity"+(loopNum+1), "type" : "area", "yAxis" : 1, "values" : data_array
};
tweetArrayObjsContainer.push(tweetArrayObj);
}
}
}
注意这一行
return GetTweetVolFactory.returnTweetVol(url+tags[i].term_id)
它在我的 for 循环里面:
for (var i=0; i<tags.length; i++)
如果我只需要循环一次,一切都运行得很好。然而,一旦有另一个标签(最多 3 个),它仍然只返回第一次循环/数据。它不会等到 for 循环完成后再返回 promise。所以我的 tweetArrayObjsContainer 总是只包含第一个标签。
答案#1
三个问题:
- 你没有从
getTagQuotes方法中返回延迟的 Promise。 - 你正在查看
i以确定是否已经完成循环,而 for 循环在第一次成功调用之前就已经完成了 (i == (tags.length - 1))。 - 你在循环的第一次迭代中调用了
return,所以你甚至都没有到第二个元素。
这是修正后的代码(还没有测试)
function getTagQuotes(tags) {
var deferred = $q.defer(); // setting the defer
var url = 'app/api/social/twitter/volume/';
var tagsComplete = 0;
for (var i=0; i<tags.length; i++) {
rawTagData = [];
GetTweetVolFactory.returnTweetVol(url+tags[i].term_id)
.success(function(data, status, headers, config) {
rawTagData.push(data);
tagsComplete++;
if (tagsComplete === tags.length) {
formatTagData(rawTagData);
deferred.resolve();
}
});
}
return deferred.promise;
}
答案#2
return deferred.promise; 应该是你的函数的返回值,而不是 GetTweetVolFactory.returnTweetVol(),因为这才是你打算进行 Promise 化的对象。
你的问题是你调用了多次 GetTweetVolFactory.returnTweetVol(),然后你需要合并所有这些异步调用以解析你的 Promise。为了做到这一点,你应该只对一次 GetTweetVolFactory.returnTweetVol() 调用进行 Promise 化:
function promisifiedTweetVol(rawTagData, urlStuff) {
var deferred = $q.defer(); // setting the defer
GetTweetVolFactory.returnTweetVol(urlStuff)
.success(function(data, status, headers, config) {
rawTagData.push(data);
// One the last loop, call formatTagData
// which fills the tweetArrayObjsContainer Array
if (loopStep === (rawTagData.length - 1)) {
formatTagData(rawTagData);
deferred.resolve();
}
});
return deferred.promise;
}
然后在循环中调用每个 promise,并返回在所有 promise 完成时解析的 promise:
function getTagQuotes(tags) {
var url = 'app/api/social/twitter/volume/';
var promises = [];
// My for loop, which only returns ONCE, even if there are 3 tags
for (var i=0; i<tags.length; i++) {
var loopStep = if;
rawTagData = [];
promises.push( promisifiedTweetVol(rawTagData, url+tags[i].term_id) );
}
// ...
return $.when(promises);
}
你的代码还有一些问题,但你应该能够根据我的提示让它运行起来。
