【问题标题】:Angular nested Promise shows an errorAngular 嵌套 Promise 显示错误
【发布时间】:2017-03-08 12:49:48
【问题描述】:

我有 2 个 API 调用。

第二次 API 调用取决于返回的属性 ID 以进行第二次 API 调用以检查这些属性中的每一个是否有停车位。

如果是这样,那么我将该属性的详细信息添加到一个对象并将该对象推送到一个数组中。

第二个 API 调用嵌套在第一个中。循环完所有属性后,我检查数组长度是否大于0,如果是,则可以在页面中显示返回的属性,否则显示错误。

问题是即使有停车返回的属性,else语句或错误函数也会执行,以及在页面上显示属性。

有没有办法在检查我的 Array 是否大于 0 之前完成嵌套的 Promise?

这是我的代码:

$scope.viewPropertyList = function(latlong) {
    $scope.locationError = false;
    var latlongArray = latlog.split('::');
    var searchLat_scope = latlongArray[0];
    var searchLon_scope = latlongArray[1];

    if (searchLat_scope && searchLon_scope) {
        var data = Property.getAllProperties({
            dest: 'property',
            apikey: API_KEY,
            lat: encodeURIComponent(searchLat_scope),
            limit: 10,
            lon: encodeURIComponent(searchLon_scope)
        }).$promise.then(function(success) {
            var propertyMarkers = [];
            $scope.dbMarkers = 0;
            for (var i = 0, l = success.property.length; i < l; i++) {
                (function(i) {
                    Property.getProperty({
                        dest: 'property',
                        propertyId: success.property[i].name,
                        apikey: API_KEY
                    }).$promise.then(function(propertyData) {

                        for (var j = 0, k = propertyData.services.length; j < k; j++) {
                            if (propertyData.services[j].name === "parking") {
                                var obj = {
                                    "propertyName": success.property[i].propertyName,
                                    "telephone": success.property[i].telephone,
                                    "postcode": success.property[i].address.postcode,
                                    "city": success.property[i].address.city,
                                    "county": success.property[i].address.county,
                                    "addressLine1": success.property[i].address.addressLine1
                                };
                                propertyMarkers.push(obj);
                            }

                        }

                        if (propertyMarkers.length != 0) {
                            $scope.dbMarkers = propertyMarkers;
                            $scope.selectedLat = searchLat_scope;
                            $scope.selectedlog = searchLon_scope;

                        } else {
                            $scope.locationErr = true;
                            $scope.errorMsg = "No properties found";
                        }

                    });

                })(i);
            }
        }, function(error) {
            $scope.locationErr = true;
            $scope.errorMsg = "Something went wrong, please try again";
        });
    }
}

【问题讨论】:

    标签: angularjs api http nested promise


    【解决方案1】:

    如果我的问题是正确的,您希望在转到成功函数检查propertyMarkers 长度之前解决所有Property.getProperty 的承诺success.property

    在这种情况下,您需要 $q.all 为您解析所有 Property.getProperty 承诺。

    在您的 for (var i = 0, l = success.property.length; i &lt; l; i++) { 中将所有承诺附加到一个数组中

    Property.getProperty({
                        dest: 'property',
                        propertyId: success.property[i].name,
                        apikey: API_KEY
                    })
    

    然后使用$q.all(arrPromises).then(function(propertyData) {进行以下检查。

    还有一点值得一提,promise chaining 可以通过$promise.then(successFn, failFn).then(successFn, failFn).then... 轻松实现。每次调用 then() 时都会创建另一个 Promise,它允许您链接到下一个 Promise 并将值传递给下一个 Promise。

    【讨论】:

      【解决方案2】:

      两个主要的事情:

      • 没有尝试聚合循环中生成的多个承诺。
      • if (propertyMarkers.length &gt; 0) {...} else {...} 嵌套太深。

      次要:

      • 一旦发现“停车”,内部迭代就会中断。如果继续下去并发现更多“停车”,则会创建重复的标记。
      $scope.viewPropertyList = function(latlong) {
          $scope.locationError = false;
          var latlongArray = latlog.split('::');
          var searchLat_scope = latlongArray[0];
          var searchLon_scope = latlongArray[1];
      
          if (searchLat_scope && searchLon_scope) {
              Property.getAllProperties({
                  dest: 'property',
                  apikey: API_KEY,
                  limit: 10,
                  lat: encodeURIComponent(searchLat_scope),
                  lon: encodeURIComponent(searchLon_scope)
              }).$promise.then(function(success) {
                  var propertyMarkers = [];
                  $scope.dbMarkers = 0;
      
                  // create an array of promises by mapping the array `success.property`.
                  var promises = success.property.map(function(prop) {
                      return Property.getProperty({
                          dest: 'property',
                          propertyId: prop.name,
                          apikey: API_KEY
                      }).$promise.then(function(propertyData) {
                          for (var j=0, k=propertyData.services.length; j<k; j++) {
                              if (propertyData.services[j].name === 'parking') {
                                  propertyMarkers.push({
                                      'propertyName': prop.propertyName,
                                      'telephone': prop.telephone,
                                      'postcode': prop.address.postcode,
                                      'city': prop.address.city,
                                      'county': prop.address.county,
                                      'addressLine1': prop.address.addressLine1
                                  });
                                  break; // 'parking' is found - no point iterating further
                              }
                          }
                      });
                  });
      
                  /* ******** */
                  // Aggregate `promises`
                  $q.all(promises).then(function() {
                      // This block is now un-nested from its original position, 
                      // and will execute when all `promises` have resolved.
                      if (propertyMarkers.length > 0) {
                          $scope.dbMarkers = propertyMarkers;
                          $scope.selectedLat = searchLat_scope;
                          $scope.selectedlog = searchLon_scope;
                      } else {
                          $scope.locationErr = true;
                          $scope.errorMsg = 'No parking found';
                      }
                  });
                  /* ******** */
      
              }).catch(function(error) {
                  $scope.locationErr = true;
                  $scope.errorMsg = 'Something went wrong, please try again';
              });
          } else {
              $scope.locationErr = true;
              $scope.errorMsg = 'Problem with lat/lng data';
          }
      }
      

      注意事项:

      • 外部迭代现在编码为 success.property.map(),它返回 promises 并避免了对 IIFE 的需要。
      • 添加了额外的错误处理

      【讨论】:

      • 这修复了它。非常感谢您对此@roamer-1888 的帮助
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-10-09
      • 1970-01-01
      • 1970-01-01
      • 2017-11-10
      • 1970-01-01
      • 2019-12-27
      相关资源
      最近更新 更多