我正在观看this AngularJS教程,该教程描述了如何使用Angular资源挂钩Twitter。 (Video tutorial)以下是示例控制器中设置的资源:
$scope.twitter = $resource('http://twitter.com/:action',
{action: 'search.json', q: 'angularjs', callback: 'JSON_CALLBACK'},
{get: {method: 'JSONP'}});
该教程显示,有几种方法可以使用get
调用从资源中恢复数据。第一种方法是将回调传递给get函数。在ajax请求返回后,将使用结果调用回调:
$scope.twitter.get(function(result) {
console.log('This was the result:', result);
});
我理解这种方法。这对我来说非常有意义。资源代表Web上可以获取数据的位置,get
只是对URL进行ajax调用,返回json,并使用json调用回调函数。 result
param是json。
这对我来说很有意义,因为很明显这是一个异步调用。也就是说,在引擎盖下,ajax调用会触发,并且调用后的代码不会被阻止,它会继续执行。然后在稍后的某个不确定点,当xhr成功时,调用回调函数。
然后教程显示了一个看起来更简单的不同方法,但我不明白它是如何工作的:
$scope.twitterResult = $scope.twitter.get();
我假设get
下面的xhr必须是异步的,但在这一行中我们将get
调用的返回值赋给变量,就像它同步返回一样。
我不理解这个错误吗?怎么可能?我觉得它很有效,但是我觉得它不行。
我理解get
可以返回某些内容,而它下面的xhr会异步处理,但如果您自己遵循代码示例,则会看到$scope.twitterResult
在执行任何后续行之前获取实际的Twitter内容。例如,如果您在该行之后立即写入console.log($scope.twitterResult)
,您将在控制台中看到来自twitter的结果,而不是稍后替换的临时值。
更重要的是,因为这是可能的,我如何编写利用相同功能的Angular服务?除了ajax请求之外,还有其他类型的数据存储需要可以在JavaScript中使用的异步调用,我希望能够以这种方式同步编写代码。例如,IndexedDB。如果我能够了解Angular内置资源的用途,我会试一试。
答案 0 :(得分:63)
$ resource不是同步的,尽管这种语法可能暗示它是:
$scope.twitterResult = $scope.twitter.get();
这里发生的是调用AngularJS后,在调用twitter.get()
后,会立即返回,结果为空数组。然后,当异步调用完成并且实际数据从服务器到达时,阵列将使用数据进行更新。 AngularJS将简单地保留对返回的数组的引用,并在数据可用时填充它。
以下是$ magic实现的片段,其中发生了“魔术”:https://github.com/angular/angular.js/blob/master/src/ngResource/resource.js#L372
这也在$resource documentation中描述:
重要的是要意识到调用$ resource对象方法会立即返回一个空引用(对象或数组,具体取决于
isArray
)。从服务器返回数据后,将使用实际数据填充现有引用。这是一个有用的技巧,因为通常将资源分配给模型,然后由视图呈现。具有空对象导致无渲染,一旦数据从服务器到达,则对象用数据填充,并且视图自动重新呈现其自身显示新数据。这意味着在大多数情况下,永远不必为动作方法编写回调函数。
答案 1 :(得分:5)
$ q也可以做到这一点。您可以使用以下内容将普通对象转换为“延迟值”:
var delayedValue = function($scope, deferred, value) {
setTimeout(function() {
$scope.$apply(function () {
deferred.resolve(value);
});
}, 1000);
return deferred.promise;
};
然后在控制器中使用它,以获得与$ scope.twitter.get()在OP示例中所做的类似的效果
angular.module('someApp', [])
.controller('someController', ['$scope', '$q', function($scope, $q) {
var deferred = $q.defer();
$scope.numbers = delayedValue($scope, deferred, ['some', 'numbers']);
}]);