$ resource`get`函数如何在AngularJS中同步工作?

我正在观看这个 AngularJS教程,介绍如何使用Angular资源连接到Twitter。 ( video教程 )以下是在示例控制器中设置的资源:

$scope.twitter = $resource('http://twitter.com/:action', {action: 'search.json', q: 'angularjs', callback: 'JSON_CALLBACK'}, {get: {method: 'JSONP'}}); 

本教程显示了使用get调用从资源获取数据的方法。 第一种方法是将callback传递给get函数。 callback将在ajax请求返回后调用结果:

 $scope.twitter.get(function(result) { console.log('This was the result:', result); }); 

我明白这个方法。 这对我来说非常有意义。 这个资源代表了一个可以获取数据的地方,只需要调用一个url的ajax,获取json,然后用json调用callback函数。 result参数是json。

这对我来说是有道理的,因为这显然是一个asynchronous调用。 也就是说,在引擎盖下,ajax调用触发,并且调用之后的代码不被阻塞,它继续执行。 然后在稍后的某个不确定点,当xhr成功时,调用callback函数。

然后教程显示了一个看起来更简单的不同方法,但我不明白它是如何工作的:

 $scope.twitterResult = $scope.twitter.get(); 

我假设下面的xhr必须是asynchronous的,但是在这一行中,我们将get调用的返回值分配给一个variables,就像它同步返回一样。

我不明白这个错误吗? 这怎么可能? 我认为它的工作真的很好,我只是不明白。

我明白, get可以返回一些东西,而它下面的xhr会asynchronous处理,但是如果你自己跟着代码示例,你会发现$scope.twitterResult在执行任何后续行之前都会得到实际的twitter内容。 例如,如果您在该行之后立即编写console.log($scope.twitterResult) ,您将看到在控制台中logging的twitter结果,而不是稍后replace的临时值。

更重要的是,因为这是可能的,我怎样才能编写一个利用这个相同function的Angular服务呢? 除了Ajax请求,还有其他types的数据存储需要asynchronous调用,可以在JavaScript中使用,我希望能够以这种风格同步编写代码。 例如,IndexedDB。 如果我可以把我的头围绕Angular的内置资源如何做,我会给它一个镜头。

$资源是不同步的,虽然这个语法可能表明它是:

 $scope.twitterResult = $scope.twitter.get(); 

这里发生的事情是,调用AngularJS将在调用twitter.get()之后立即返回,结果是一个空数组。 然后,当asynchronous调用完成并且真实数据从服务器到达时,数组将被更新为数据 。 AngularJS将简单地保留对返回数组的引用,并在数据可用时填充它。

这里是“魔术”发生的$资源实施的片段: https : //github.com/angular/angular.js/blob/master/src/ngResource/resource.js#L372

这也在$ resource文档中描述:

认识到调用一个$ resource对象方法立即返回一个空引用(依赖于isArray对象或数组)是很重要的。 一旦数据从服务器返回,现有的引用将填充实际的数据。 这是一个很有用的技巧,因为通常资源被分配到一个模型,然后由视图渲染。 有一个空对象导致不呈现,一旦数据从服务器到达,然后对象填充数据和视图自动重新呈现自己显示新的数据。 这意味着在大多数情况下,不必为动作方法编写callback函数。

$ 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']); }]);