我有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);
}
控制台:
答案 0 :(得分: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
中传递的函数中。
答案 1 :(得分:0)
更新的解决方案:
您必须等到所有的诺言都解决后才能使用结果。您可以使用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.log
移到.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) {
});
答案 2 :(得分:0)
原因是“异步代码” 。$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
}
答案 3 :(得分:0)
是的,以上两个答案都是正确的。您的代码是异步的。您正在登录控制台(并在从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) {
});
});
}
注意:以专业的方式使用Promises,因为如果使用过多的回调会导致 Callback Hells 。但是,如果您真的想了解承诺背后的逻辑,则可以使用或了解回调。