【问题标题】:parsing json array not working properly in angularjs解析json数组在angularjs中无法正常工作
【发布时间】:2018-08-07 05:52:44
【问题描述】:

我有 Angular js 应用程序。我正在尝试使用 angular.forEach 解析 json 数组。它表现出奇怪的行为。

当我试图控制它时,它正在显示数据,但是当我试图用长度来控制它时,它显示长度为 0。

我只想在循环外输出。我怎样才能做到这一点?

谁能帮我解决这个问题?

function loadRelease() {
    $scope.datas.releaseData = [];
    angular.forEach($scope.datas.repositoryData, function(value, key) {
        GitHubService.getDevMasterReleaseDate(value.url)
            .then(function(responseRepo) {
                var dataToOperate = [];
                var dataJson = {
                    'repoName': value.name
                    , 'masterArray': []
                    , 'devArray': []
                }

                angular.forEach(responseRepo.data, function(value, key) {
                    if (value.target_commitish == 'master') {
                        dataJson.masterArray.push(value);
                    } else {
                        dataJson.devArray.push(value);
                    }
                });

                $scope.datas.releaseData.push(dataJson);
            }, function(error) {

            });

    });
    console.log($scope.datas.releaseData);
    console.log('length :: ' + $scope.datas.releaseData.length);

}

控制台:

【问题讨论】:

  • 将控制台移入then

标签: javascript angularjs json for-loop


【解决方案1】:

对象/数组通过引用传递,原始值通过 按 JavaScript 中的值。

这是对异常的正确解释(当然不是真的):

function loadRelease() {
    $scope.datas.releaseData = []; // LINE A
    angular.forEach($scope.datas.repositoryData, function(value, key) {
    GitHubService.getDevMasterReleaseDate(value.url).then(function(responseRepo) {
            var dataToOperate = [];
            var dataJson = {
                'repoName' : value.name,
                'masterArray' : [],
                'devArray' : [] 
            }

            angular.forEach(responseRepo.data, function(value, key) {
                if(value.target_commitish == 'master') {
                    dataJson.masterArray.push(value);
                } else {
                    dataJson.devArray.push(value);
                }
            });

            $scope.datas.releaseData.push(dataJson); // LINE B
        }, function(error) {

        });

    });
    console.log($scope.datas.releaseData); // LINE C
    console.log('length :: ' + $scope.datas.releaseData.length); //LINE D

}

在您的代码中,您正在做的是控制台记录在 LINE A 上初始化的空数组的长度(在上面的代码中标记)。长度是一个原始值,它不作为引用传递,而是按值传递,因此对它的任何更新都不会反映在您的console.log 中。但是,当您在 LINE C 上记录您的实际数组时,它通过引用 console.log 方法传递,并且当传递的数组在 GitHubService.getDevMasterReleaseDate 的异步调用的承诺解决后得到更新时,它的值在 console.log 中得到更新方法也是因为它传递的是引用而不是值。如果您想获得预期的行为,您必须将控制台日志移动到 .then 中传递的函数内。

【讨论】:

    【解决方案2】:

    更新的解决方案:

    在尝试使用结果之前,您必须等到所有的承诺都得到解决。你可以通过Promise.all 做到这一点:

    function loadRelease() {
        $scope.datas.releaseData = [];
        var promises = [];
        angular.forEach($scope.datas.repositoryData, function(value, key) {
            promises.push(GitHubService.getDevMasterReleaseDate(value.url).then(function(responseRepo) {
                var dataToOperate = [];
                var dataJson = {
                    'repoName' : value.name,
                    'masterArray' : [],
                    'devArray' : [] 
                }
    
                angular.forEach(responseRepo.data, function(value, key) {
                    if(value.target_commitish == 'master') {
                        dataJson.masterArray.push(value);
                    } else {
                        dataJson.devArray.push(value);
                    }
                });
    
                $scope.datas.releaseData.push(dataJson);
            }, function(error) {
    
            }));
        });
        Promise.all(promises).then(() => {
            console.log($scope.datas.releaseData);
            console.log('length :: ' + $scope.datas.releaseData.length);
        });
    }
    

    上一个答案:

    您在对 API 的异步调用之外记录结果。

    一旦异步调用返回结果(当您注销对象/数组时),Chrome 控制台实际上会更新记录的值,这就是第一个日志有结果的原因。然而,第二个是一个原语,因此它在记录时保持为真实值,即 0。

    如果您想要正确的输出,请将您的 console.logs 移到 .then 函数内。

    GitHubService.getDevMasterReleaseDate(value.url).then(function(responseRepo) {
        ...
        $scope.datas.releaseData.push(dataJson);
        console.log($scope.datas.releaseData);
        console.log('length :: ' + $scope.datas.releaseData.length);
    }, function(error) {
    
    });
    

    【讨论】:

    • 我想在循环之外获取这些值。我该怎么做?
    • @SimonK 答案很好,但代码开销很大。它可以做得更简单。
    • OP 不想要每个循环之后的值,只需要所有循环完成后。这是最简单的方法
    【解决方案3】:

    是的,以上两个答案都是正确的。您的代码是异步的。您正在登录控制台(并在从 API 获取之前使用 $scope.datas.releaseData。) 如果您真的想在 .then() 之外访问 $scope.datas.releaseData,请将函数作为回调传递,然后在 .then() 函数内部调用此函数。 从下面的代码中获取想法:

    var logResponse = function(){
    
      console.log($scope.datas.releaseData);
      console.log('length :: ' + $scope.datas.releaseData.length);
    
    }
    
    loadRelease(logResponse); //pass variable containing your function
    
    function loadRelease(myCallBack) {
      $scope.datas.releaseData = [];
      angular.forEach($scope.datas.repositoryData, function(value, key) {
        GitHubService.getDevMasterReleaseDate(value.url)
          .then(function(responseRepo) {
            var dataToOperate = [];
            var dataJson = {
              'repoName': value.name
              , 'masterArray': []
              , 'devArray': []
            }
    
            angular.forEach(responseRepo.data, function(value, key) {
              if (value.target_commitish == 'master') {
                dataJson.masterArray.push(value);
              } else {
                dataJson.devArray.push(value);
              }
            });
    
            $scope.datas.releaseData.push(dataJson);
            myCallBack(); //called here
          }, function(error) {
    
          });
    
      });
    }
    

    注意:以专业的方式使用 Promise,因为如果过度使用回调,会导致 回调地狱。但是,如果你真的想了解 Promise 背后的逻辑,你可以使用或了解 Callbacks。

    【讨论】:

      【解决方案4】:

      原因是“异步代码”$scope.datas.releaseData 的值是在异步代码/API/Ajax 中设置的{GitHubService.getDevMasterReleaseDate}

      最后一行第二行为控制台编写的代码在执行时没有值,但在 chrome 中,如果展开打印的对象,它会显示该对象的最新值。为了清楚起见,尝试用console.log(JSON.stringify($scope.datas.releaseData))替换倒数第二行@

      但最后一行的控制台是一个整数,它显示了执行时对象长度的正确值。

      如果你想要 API 之外的对象的值

      创建一个函数**(例如 processReleaseData())** 并在推送代码之后调用它。使用该函数,您将收到变量的值($scope.datas.releaseData)

      function loadRelease() {
          $scope.datas.releaseData = [];
          angular.forEach($scope.datas.repositoryData, function(value, key) {
              GitHubService.getDevMasterReleaseDate(value.url)
                  .then(function(responseRepo) {
                      var dataToOperate = [];
                      var dataJson = {
                          'repoName': value.name
                          , 'masterArray': []
                          , 'devArray': []
                      }
      
                      angular.forEach(responseRepo.data, function(value, key) {
                          if (value.target_commitish == 'master') {
                              dataJson.masterArray.push(value);
                          } else {
                              dataJson.devArray.push(value);
                          }
                      });
      
                      $scope.datas.releaseData.push(dataJson);
                      processReleaseData($scope.datas.releaseData);
                      //can call processReleaseData() directly also without 
                      //passing arg
                  }, function(error) {
      
                  });
          });
      
          console.log($scope.datas.releaseData);
          console.log('length :: ' + $scope.datas.releaseData.length);
      }
      
      function processReleaseData(releaseData){
          //Do here whatever you want to do with releaseData;
          //You can also directly access the $scope.datas.releaseData here
      }
      

      【讨论】:

      • 我想在循环之外获取这些值。我该怎么做?
      • @SangramBadi 我已经更新了我的答案,现在看看,你可以轻松简单地实现你想要的。
      • 我这样做了,如果我把那个函数放在循环内,它会在循环内工作,但我希望这个函数在循环外。正如@Simon K 回答使用promise 它的工作时间
      • @SangramBadi 我更新了答案。你试过这样做吗?
      • @Ronit,OP 不想为外部angular.forEach 的每次迭代调用一个函数,他们只想调用一次,并且只有在所有承诺都得到解决之后。
      猜你喜欢
      • 2021-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多