我尝试构建一个可以获取CSV数据,将其转换为行,然后为每行发出API请求,将格式化结果添加到输出字符串的服务。
换句话说,我的(Coffeescript)代码如下所示:
$s.batchFetch = ->
return unless $s.csv
$s.output = ''
for row in $s.csv.split("\n")
$s._addToOutput(row)
$s._addToOutput()
函数正确地使用该行进行API调用,对其进行格式化,并将格式化的响应添加到我的输出字符串($s.output
)。基本上,这样的事情:
$s._addToOutput (row) = ->
formattedResponse = ''
$http.get("api/request/path/row-specific-whatever")
.success (res) ->
formattedResponse = $s._format(res)
.then ->
$s.output += formattedResponse
问题是输出字符串中格式化响应的顺序似乎是随机/变量。对于某些行,API看起来比其他行更快/更长,并且首先添加的响应首先被添加 - 不考虑我的rows
变量的顺序。
我认为解决方案是某种角度承诺链接,la:
$s._addToOutput(row).then ->
$s._addToOutput(secondRow).then ->
$s._addToOutput(thirdRow).then ->
...
但我有一个不可预测的行数,我希望能够基本上只是说:"为每行做一次API调用,一个接一个强力>"
有人能想到一个好方法吗?我现在可能不会直接思考,但我很难过。
谢谢!
萨莎
编辑 - 给了ryeballar的解决方案,但我的实现并没有真正阻止重新排序的问题。很确定这是我的错误,所以如果有人发现任何事情,请告诉我:
(注意,我必须调整解决方案,因为我连续两次请求每一行 - 第一个用于"场地"第二个用于"照片" of我找到的地点。另外,yamlify
=='格式'。)
$s.batchFetch = function() {
if (!$s.csv) {
return;
}
$s.output = '';
return $scope.csv.split("\n").reduce(function(promise, row) {
var rowPromise, split;
split = row.split(',');
rowPromise = $s._getVenue(split[0], split[1]).success(function(res) {
var venue;
venue = res.response.groups[0].items[0].venue;
$s._getPhoto(venue).success(function(resp) {
var photo;
photo = $s._photoUrl(resp);
return $s.output += $s._yamlify(venue, row, photo);
});
});
return promise.then(rowPromise);
}, $q.when());
};
注意 - getVenue()
和getPhoto()
只是对$http
的调用,因此他们会返回回复success
,error
,then
的对象}等等photoUrl()
只是一个辅助函数,用于将响应对象解析为新的API路径。
最近的努力,仍在随机重新排序 - 是_getVenue
和_getPhoto
只是$http.get(path)
来电:
$s.batchFetch = function() {
if (!$s.csv) {
return;
}
$s.output = '';
return $s.csv.split("\n").reduce(function(promise, row) {
var rowPromise, split;
split = row.split(',');
rowPromise = $s._getVenue(split[0], split[1]).success(function(res) {
var venue;
venue = res.response.groups[0].items[0].venue;
return $s._getPhoto(venue).success(function(resp) {
var photo;
photo = $s._photoUrl(resp);
return $s.output += $s._yamlify(venue, row, photo);
});
});
return promise.then(rowPromise);
}, $q.when());
};
答案 0 :(得分:2)
您可以通过从一个到另一个调用每个承诺来使用.reduce()
。初始值是一个承诺,它将立即解析$q.when()
,然后调用rowPromise
,这也是一个承诺,每当调用then()
时都会产生链接效果。
.controller('CsvController', function($scope, $q) {
$scope.csv = '.....';
$scope._format = function() {/*...*/};
$scope.batchFetch = function() {
$scope.output = '';
return $scope.csv.split('\n').reduce(function(promise, row) {
return promise.then(function() {
return $http.get("api/request/path/row-specific-whatever", {row: row})
.success(function(res) {
$scope.output += $scope._format(res);
});
});
}, $q.when());
};
});
<强>更新强>
我已经更新了上面的代码,它应该是一个回调,而不是在迭代过程中调用$http
请求。所以你的代码应该是这样的:
$s.batchFetch = function() {
if (!$s.csv) {
return;
}
$s.output = '';
return $s.csv.split("\n").reduce(function(promise, row) {
return promise.then(function() {
var split = row.split(',');
return $s._getVenue(split[0], split[1]).success(function(res) {
var venue = res.response.groups[0].items[0].venue;
return $s._getPhoto(venue).success(function(resp) {
var photo = $s._photoUrl(resp);
return $s.output += $s._yamlify(venue, row, photo);
});
});
});
}, $q.when());
};
当我阅读你的代码时,它似乎正在落入回调地狱。或者,最好像这样构造它:
$s.batchFetch = function() {
if (!$s.csv) {
return;
}
$s.output = '';
return $s.csv.split("\n").reduce(function(promise, row) {
var split, venue, photo;
return promise
.then(function() {
split = row.split(',');
return $s._getVenue(split[0], split[1]);
}).then(function(response) {
venue = response.data.response.groups[0].items[0].venue;
return $s._getPhoto(venue);
}).then(function(response) {
photo = $s._photoUrl(response.data);
return $s.output += $s._yamlify(venue, row, photo);
});
}, $q.when());
};