1

我正在尝试构建一个可以获取 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变量的顺序。

我认为解决方案是某种 Angular 承诺链,例如:

$s._addToOutput(row).then ->
  $s._addToOutput(secondRow).then ->
    $s._addToOutput(thirdRow).then ->
      ...

但是我有一个不可预测的行数,我很想能够基本上只是说:“对每一行进行 API 调用,一个接一个。”

谁能想到一个好的方法来做到这一点?我现在可能只是想不通,但我很难过。

谢谢!

萨沙

编辑——试一试 ryeballar 的解决方案,但我对它的实施实际上并没有停止重新排序问题。很确定这是我的错误,所以如果有人发现任何东西,请告诉我:

(注意,我必须调整解决方案,因为我对每一行提出了两个连续的请求——第一个请求是“场地”,第二个请求是我找到的场地的“照片”。另外,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,因此它们返回响应successerrorthenphotoUrl()的对象只是一个帮助函数,用于将响应对象解析为新的 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());
};
4

1 回答 1

2

您可以.reduce()通过从一个到下一个调用每个承诺来使用。初始值是一个承诺,它将立即解析$q.when()然后调用rowPromise,这也是一个承诺,每当then()调用每个 s 时都会产生链接效果。

.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());
};
于 2014-08-31T02:24:35.157 回答