Angular $q 在 http 请求之前执行 "then"
Angular $q execute "then" before http request
几个小时以来,我都快被这个搞疯了。
我有一个 angular 服务工厂可以从我的 API:
获取地址
App.factory('storesService', ['$http', '$q', 'endpoint', function ($http, $q, endpoint) {
var deferred = $q.defer();
return {
addresses: function (store_id) {
$http.get(endpoint.store.addresses, {
params: {
id: store_id
}
})
.success(function (data) {
console.log('Data from API:' + data);
deferred.resolve(data);
})
.error(function () {
deferred.reject();
});
return deferred.promise;
}
};
}]);
此服务在我的控制器中用于获取特定商店的地址:
$scope.loadAddresses = function (store_id) {
var load = storesService.addresses(store_id);
load.then(function (data) {
console.log('Deferred data:' + data);
$scope.addresses = data.addresses;
});
};
在我看来,我有 ng-init="loadAddresses(store_id)"
,store_id
是正确的值。
我也在使用 angular-xeditable(select-本地)来管理我的商店 selection。
我在我的视图中添加了 onaftersave='storeChanged(store.id)'
以获取用户编辑的商店 ID select 并且 return 正确地使用了新 ID。
我的storeChanged
函数很简单,它基本上运行一个新的请求到API:
$scope.storeChanged = function (store_id) {
$scope.loadAddresses(store_id);
};
发生了什么:
一开始,ng-init
我看对了the console.log
,首先是服务端的,然后是控制器端的。
一旦我 select 我的 select 的另一家商店,我首先看到来自控制器的 console.log
,然后是来自服务的
基本上controller里面的数据没有更新,我不明白为什么会这样...
您正在尝试重新解决一个承诺,但您做不到。您只需创建一个 deferred
供每个请求使用。它应该在 addresses
函数内部,以便为每个请求创建一个新函数,但无论如何您都不需要它,因为 $http
已经创建并且 return 已经是一个承诺。您需要 return 来自 $http
的承诺,而不是创建一个新的承诺。请参阅此 post 以获得更好的理解:What is the explicit promise construction antipattern and how do I avoid it?
addresses: function (store_id) {
return $http.get(endpoint.store.addresses, {
params: {
id: store_id
}
}).then(function(resp) {
console.log('Data from API:' + resp.data);
return resp.data;
});
}
您在服务中全局定义了延迟,因此只有一个全局承诺。因为承诺只能被解决或拒绝一次,所以在您第一次 http 调用后它将永远保持 resolved/rejected。要修复,只需将 var deferred = $q.defer();
行移动到您的服务函数中:
App.factory('storesService', ['$http', '$q', 'endpoint', function ($http, $q, endpoint) {
return {
addresses: function (store_id) {
var deferred = $q.defer();
$http.get(endpoint.store.addresses, {
params: {
id: store_id
}
})
.success(function (data) {
console.log('Data from API:' + data);
deferred.resolve(data);
})
.error(function () {
deferred.reject();
});
return deferred.promise;
}
};
}]);
您已经为可能的许多请求创建了一个延迟。您第一次发出请求时它会起作用,但之后它会立即 return,因为您设置的一个承诺已经解决。实际上,与此类似的模式对于缓存非常有用。
$http
已经 return 是一个承诺。您无需特意使用 $q
App.factory('storesService', ['$http', 'endpoint', function ($http, endpoint) {
return {
addresses: function (store_id) {
return $http.get(endpoint.store.addresses, {
params: {
id: store_id
}
}).then(function(response){
//Chain an extra promise here to clean up the response to just return the data.
return response.data;
})
}
};
}]);
几个小时以来,我都快被这个搞疯了。
我有一个 angular 服务工厂可以从我的 API:
获取地址App.factory('storesService', ['$http', '$q', 'endpoint', function ($http, $q, endpoint) {
var deferred = $q.defer();
return {
addresses: function (store_id) {
$http.get(endpoint.store.addresses, {
params: {
id: store_id
}
})
.success(function (data) {
console.log('Data from API:' + data);
deferred.resolve(data);
})
.error(function () {
deferred.reject();
});
return deferred.promise;
}
};
}]);
此服务在我的控制器中用于获取特定商店的地址:
$scope.loadAddresses = function (store_id) {
var load = storesService.addresses(store_id);
load.then(function (data) {
console.log('Deferred data:' + data);
$scope.addresses = data.addresses;
});
};
在我看来,我有 ng-init="loadAddresses(store_id)"
,store_id
是正确的值。
我也在使用 angular-xeditable(select-本地)来管理我的商店 selection。
我在我的视图中添加了 onaftersave='storeChanged(store.id)'
以获取用户编辑的商店 ID select 并且 return 正确地使用了新 ID。
我的storeChanged
函数很简单,它基本上运行一个新的请求到API:
$scope.storeChanged = function (store_id) {
$scope.loadAddresses(store_id);
};
发生了什么:
一开始,ng-init
我看对了the console.log
,首先是服务端的,然后是控制器端的。
一旦我 select 我的 select 的另一家商店,我首先看到来自控制器的 console.log
,然后是来自服务的
基本上controller里面的数据没有更新,我不明白为什么会这样...
您正在尝试重新解决一个承诺,但您做不到。您只需创建一个 deferred
供每个请求使用。它应该在 addresses
函数内部,以便为每个请求创建一个新函数,但无论如何您都不需要它,因为 $http
已经创建并且 return 已经是一个承诺。您需要 return 来自 $http
的承诺,而不是创建一个新的承诺。请参阅此 post 以获得更好的理解:What is the explicit promise construction antipattern and how do I avoid it?
addresses: function (store_id) {
return $http.get(endpoint.store.addresses, {
params: {
id: store_id
}
}).then(function(resp) {
console.log('Data from API:' + resp.data);
return resp.data;
});
}
您在服务中全局定义了延迟,因此只有一个全局承诺。因为承诺只能被解决或拒绝一次,所以在您第一次 http 调用后它将永远保持 resolved/rejected。要修复,只需将 var deferred = $q.defer();
行移动到您的服务函数中:
App.factory('storesService', ['$http', '$q', 'endpoint', function ($http, $q, endpoint) {
return {
addresses: function (store_id) {
var deferred = $q.defer();
$http.get(endpoint.store.addresses, {
params: {
id: store_id
}
})
.success(function (data) {
console.log('Data from API:' + data);
deferred.resolve(data);
})
.error(function () {
deferred.reject();
});
return deferred.promise;
}
};
}]);
您已经为可能的许多请求创建了一个延迟。您第一次发出请求时它会起作用,但之后它会立即 return,因为您设置的一个承诺已经解决。实际上,与此类似的模式对于缓存非常有用。
$http
已经 return 是一个承诺。您无需特意使用 $q
App.factory('storesService', ['$http', 'endpoint', function ($http, endpoint) {
return {
addresses: function (store_id) {
return $http.get(endpoint.store.addresses, {
params: {
id: store_id
}
}).then(function(response){
//Chain an extra promise here to clean up the response to just return the data.
return response.data;
})
}
};
}]);