欢迎来到 promise(d) hell ;-)

Welcome to promise(d) hell ;-)

我想使用 promises 异步加载一些文件并编写了这个解决方案:

function create(ids, $q, http) {
      var promises = [];
      _.each(ids, function(id) {
        var item = http.get('catalog/' + id + '.json').then(function (response) {
          return {id: id, item: response.data};
        }, function(reason) {
          console.log(reason.config.url, reason.statusText, reason.status);
        });
        promises.push(item);
      });

      return $q.all(promises).then(function(values) {
        var catalog = {};
        var svgPromises = [];
        _.each(values, function(value) {
          catalog[value.id] = value.item;

          var svg = http.get('catalog/' + value.item.svg).then(function (response) {
            return {id: value.id, svg: response.data};
          }, function(reason) {
            console.log(reason.config.url, reason.statusText, reason.status);
          });
          svgPromises.push(svg);
        });
        return $q.all(svgPromises).then(function(values) {
          _.each(values, function(value) {
            catalog[value.id].svg = value.svg;
          });
          return catalog;
        });
      });
    }

我不太喜欢它,我知道我可以使用地图让它变得更好一点,但我不相信我做对了。有人知道怎么做更好吗?

创建第三个延迟对象怎么样,然后我们只在所有调用完成后才解析延迟对象? (由于我无法测试,下面的代码可能有一些错误,但希望思路清晰)

function create(ids, $q, http) {
  var promises = [];
  var catalog = {};

  _.each(ids, function (id) {
    var svgDef = $q.defer();
    http.get('catalog/' + id + '.json')
      .then(
      function (response) {
        var value = {id: id, item: response.data};
        catalog[value.id] = value.item;
        http.get('catalog/' + value.item.svg)
          .then(
          function (response) {
            catalog[value.id].svg = response.data;
            svgDef.resolve(catalog[value.id]);
          },
          function (reason) {
            console.log(reason.config.url, reason.statusText, reason.status);
            svgDef.reject(reason);
          });
      },
      function (reason) {
        console.log(reason.config.url, reason.statusText, reason.status);
        svgDef.reject(reason);
      });
    promises.push(svgDef.promise);
  });

  return $q.all(promises)
    .then(function () {
      return catalog;
    })
}
function create(ids, $q, http) {
  var catalog = {};
  return $q.all(_.map(ids, function(id) {
    return http.get('catalog/' + id + '.json')
      .then(function(response) {
        catalog[id] = {id: id, item: response.data};
        return http.get('catalog/' + response.data.svg);
      })
      .then(function(response) {
        catalog[id].svg = response.data;
      })
      .catch(function(e) {
        console.log(e.config.url, e.statusText, e.status);
      });
  })).then(function() {
    return catalog;
  });
}