使用 $q promise 就像从 $resource 返回的 promise
use the $q promise like the promise returned from $resource
使用 angular 的 $resource promise,我可以将 promise 重新分配给变量并使用它,而无需在成功函数中将 promise 的结果分配给变量。我想知道我是否可以用 $q?
达到同样的效果
示例
.service("rest", function($resource){
return {
user: $resource( "http://some.com/url")
}
})
.controller("myCtrl", function($scope, rest){
$scope.user = rest.user.get(); <-- This is what I want to be able to do with $q
})
简短回答:否
$resource
界面是专门为允许这种 'futures' 行为而设计的。当您调用 .get()
时,它 returns 一个占位符对象,当它可用时将填充数据。
因为 $resource
是一个内部 Angular 工厂,它知道何时触发摘要循环,这让您看起来可以从一开始就使用 $scope.user
。实际上,在服务器收到 HTTP 响应之前,它不会填充数据。
另一方面,承诺是一种通用机制。当值到达时,它不知道将其值存储在哪种占位符对象中。它也不会到达什么样的价值。所以 promise 公开了一系列回调方法,我们可以使用这些方法让我们知道 promise 何时准备就绪。
长答案:某种程度上(您可以使用承诺来构建像这样工作的接口)
这种机制之所以有效,是因为 Angular 对作用域进行脏检查的方式。当异步事件发生时,需要让 Angular 知道它应该检查是否有任何更改并且需要更新它的视图。
当数据从我们的 HTTP 响应到达时,$resource
工厂负责通知 Angular。这意味着 $scope.user
对象将在到达后立即显示在您的视图中。 $resource
负责在异步事件发生时让事情发生。在这种情况下,异步事件是随数据到达的 HTTP 响应。
使用 promises 时,您负责在异步事件发生时让事情发生。 promise 将特定于 Angular,因此 promises 有一个通用接口来处理可能发生在 promise 上的不同异步事件。当其中之一发生时,您的工作就是完成工作,这就是为什么简短的回答是否定的。
但是,如果您正在实施 factory/service/provider,这种行为是可取的,这是可能的。
让我们创建一个火箭工厂来创建火箭实例,稍后将添加它们的零件,就像 $resource
使用 $q
工厂一样。
app.factory('Rocket', function(Junkyard) {
return function(name) {
var rocket = {};
rocket.name = name || 'Boring Rocket';
rocket.parts = [];
rocket.promise = Junkyard.getParts();
// Junkyard.getParts returns a $q promise
// which will be resolved with an object
// of things that can be attached to the rocket.
//
// It might look something like this
// [
// { name: "thrusters", "quantity": 3 },
// { name: "engines", "quantity": 100 },
// { name: "robots", "quantity": 2 }
// ]
rocket.promise.then(function(parts) {
parts.forEach(function(part) {
rocket.parts.push(part);
});
});
return rocket;
};
});
现在我们可以像 $resource
一样使用我们的新工厂:
function MyController($scope, Rocket) {
$scope.rocket = Rocket('Top Rocket');
// we can use $scope.rocket here!
$scope.rocket.name = 'Even Better Rocket';
// but it won't have the properties from
// Junkyard.getParts yet.
}
我们可以将这些值直接模板化到我们的视图中。
<section ng-controller='MyController'>
<h1 ng-bind='rocket.name'></h1>
<table>
<th>
<td>Name</td>
</th>
<th>Description</th>
<tr ng-repeat='part in rocket.parts'>
<td ng-bind='part.name'></td>
<td ng-bind='part.description'></td>
</tr>
</table>
</section>
一旦 promise 解决,属性将被添加到火箭并且范围摘要将被 $q
触发,因为 $q
知道异步事件刚刚发生。
将承诺直接分配给变量并在模板中呈现它们的功能已从 Angular 中删除。请参阅此重大更改:Templates no longer automatically unwrap promises。相反,当承诺已解决或被拒绝时,您必须在回调中分配范围 属性。
您可以 return 更新一个对象而不是承诺。 jsfiddle
var getUser = function(base) {
var user = base || {};
// replace with actual request
$timeout(function() {
// make sure to use angular.copy so the same object is used
angular.copy({
id: 1,
username: 'anon',
roles: [
{ id: 1, title: 'user' },
{ id: 2, title: 'admin' },
{ id: 3, title: 'editor' }
]
}, user);
}, 3000);
return user;
};
$scope.user = getUser({roles: []});
这样做有效(它是一个 coffeescript),
service.getSomeData = () ->
data = {}
$http.get("/getSomeData").then (resp) ->
angular.copy(resp.data, data)
return data
在控制器中你可以这样做
$scope.data = service.getSomeData()
使用 angular 的 $resource promise,我可以将 promise 重新分配给变量并使用它,而无需在成功函数中将 promise 的结果分配给变量。我想知道我是否可以用 $q?
达到同样的效果示例
.service("rest", function($resource){
return {
user: $resource( "http://some.com/url")
}
})
.controller("myCtrl", function($scope, rest){
$scope.user = rest.user.get(); <-- This is what I want to be able to do with $q
})
简短回答:否
$resource
界面是专门为允许这种 'futures' 行为而设计的。当您调用 .get()
时,它 returns 一个占位符对象,当它可用时将填充数据。
因为 $resource
是一个内部 Angular 工厂,它知道何时触发摘要循环,这让您看起来可以从一开始就使用 $scope.user
。实际上,在服务器收到 HTTP 响应之前,它不会填充数据。
另一方面,承诺是一种通用机制。当值到达时,它不知道将其值存储在哪种占位符对象中。它也不会到达什么样的价值。所以 promise 公开了一系列回调方法,我们可以使用这些方法让我们知道 promise 何时准备就绪。
长答案:某种程度上(您可以使用承诺来构建像这样工作的接口)
这种机制之所以有效,是因为 Angular 对作用域进行脏检查的方式。当异步事件发生时,需要让 Angular 知道它应该检查是否有任何更改并且需要更新它的视图。
当数据从我们的 HTTP 响应到达时,$resource
工厂负责通知 Angular。这意味着 $scope.user
对象将在到达后立即显示在您的视图中。 $resource
负责在异步事件发生时让事情发生。在这种情况下,异步事件是随数据到达的 HTTP 响应。
使用 promises 时,您负责在异步事件发生时让事情发生。 promise 将特定于 Angular,因此 promises 有一个通用接口来处理可能发生在 promise 上的不同异步事件。当其中之一发生时,您的工作就是完成工作,这就是为什么简短的回答是否定的。
但是,如果您正在实施 factory/service/provider,这种行为是可取的,这是可能的。
让我们创建一个火箭工厂来创建火箭实例,稍后将添加它们的零件,就像 $resource
使用 $q
工厂一样。
app.factory('Rocket', function(Junkyard) {
return function(name) {
var rocket = {};
rocket.name = name || 'Boring Rocket';
rocket.parts = [];
rocket.promise = Junkyard.getParts();
// Junkyard.getParts returns a $q promise
// which will be resolved with an object
// of things that can be attached to the rocket.
//
// It might look something like this
// [
// { name: "thrusters", "quantity": 3 },
// { name: "engines", "quantity": 100 },
// { name: "robots", "quantity": 2 }
// ]
rocket.promise.then(function(parts) {
parts.forEach(function(part) {
rocket.parts.push(part);
});
});
return rocket;
};
});
现在我们可以像 $resource
一样使用我们的新工厂:
function MyController($scope, Rocket) {
$scope.rocket = Rocket('Top Rocket');
// we can use $scope.rocket here!
$scope.rocket.name = 'Even Better Rocket';
// but it won't have the properties from
// Junkyard.getParts yet.
}
我们可以将这些值直接模板化到我们的视图中。
<section ng-controller='MyController'>
<h1 ng-bind='rocket.name'></h1>
<table>
<th>
<td>Name</td>
</th>
<th>Description</th>
<tr ng-repeat='part in rocket.parts'>
<td ng-bind='part.name'></td>
<td ng-bind='part.description'></td>
</tr>
</table>
</section>
一旦 promise 解决,属性将被添加到火箭并且范围摘要将被 $q
触发,因为 $q
知道异步事件刚刚发生。
将承诺直接分配给变量并在模板中呈现它们的功能已从 Angular 中删除。请参阅此重大更改:Templates no longer automatically unwrap promises。相反,当承诺已解决或被拒绝时,您必须在回调中分配范围 属性。
您可以 return 更新一个对象而不是承诺。 jsfiddle
var getUser = function(base) {
var user = base || {};
// replace with actual request
$timeout(function() {
// make sure to use angular.copy so the same object is used
angular.copy({
id: 1,
username: 'anon',
roles: [
{ id: 1, title: 'user' },
{ id: 2, title: 'admin' },
{ id: 3, title: 'editor' }
]
}, user);
}, 3000);
return user;
};
$scope.user = getUser({roles: []});
这样做有效(它是一个 coffeescript),
service.getSomeData = () ->
data = {}
$http.get("/getSomeData").then (resp) ->
angular.copy(resp.data, data)
return data
在控制器中你可以这样做
$scope.data = service.getSomeData()